美文网首页
偷用FloatActionButton的源码实现可更改颜色的阴影

偷用FloatActionButton的源码实现可更改颜色的阴影

作者: 凌空之鹤 | 来源:发表于2019-10-31 10:03 被阅读0次

    FloatActionButton用来做阴影的主要是ShadowDrawableWrapper,这个功能相对独立,可以直接把这个类和他继承的DrawableWrapper 拷出来放在自己的包下面,然后重新导包就行了。


    image.png

    这个图上面的三个颜色,我们可以自定义,也就是阴影的渐变三色。
    源码:
    public class ShadowDrawableWrapper extends DrawableWrapper {

    static final double COS_45 = Math.cos(Math.toRadians(45.0D));
    static final float SHADOW_MULTIPLIER = 1.5F;
    static final float SHADOW_TOP_SCALE = 0.25F;
    static final float SHADOW_HORIZ_SCALE = 0.5F;
    static final float SHADOW_BOTTOM_SCALE = 1.0F;
    final Paint cornerShadowPaint;
    final Paint edgeShadowPaint;
    final RectF contentBounds;
    float cornerRadius;
    Path cornerShadowPath;
    float maxShadowSize;
    float rawMaxShadowSize;
    float shadowSize;
    float rawShadowSize;
    private boolean dirty = true;
    private final int shadowStartColor;
    private final int shadowMiddleColor;
    private final int shadowEndColor;
    private boolean addPaddingForCorners = true;
    private float rotation;
    private boolean printedShadowClipWarning = false;
    
    public ShadowDrawableWrapper(Context context, Drawable content, float radius, float shadowSize, float maxShadowSize) {
        super(content);
        this.shadowStartColor = ContextCompat.getColor(context, R.color.design_fab_shadow_start_color);
        this.shadowMiddleColor = ContextCompat.getColor(context, R.color.design_fab_shadow_mid_color);
        this.shadowEndColor = ContextCompat.getColor(context, R.color.design_fab_shadow_end_color);
        this.cornerShadowPaint = new Paint(5);
        this.cornerShadowPaint.setStyle(Paint.Style.FILL);
        this.cornerRadius = (float)Math.round(radius);
        this.contentBounds = new RectF();
        this.edgeShadowPaint = new Paint(this.cornerShadowPaint);
        this.edgeShadowPaint.setAntiAlias(false);
        this.setShadowSize(shadowSize, maxShadowSize);
    }
    
    private static int toEven(float value) {
        int i = Math.round(value);
        return i % 2 == 1 ? i - 1 : i;
    }
    
    public void setAddPaddingForCorners(boolean addPaddingForCorners) {
        this.addPaddingForCorners = addPaddingForCorners;
        this.invalidateSelf();
    }
    
    public void setAlpha(int alpha) {
        super.setAlpha(alpha);
        this.cornerShadowPaint.setAlpha(alpha);
        this.edgeShadowPaint.setAlpha(alpha);
    }
    
    protected void onBoundsChange(Rect bounds) {
        this.dirty = true;
    }
    
    public void setShadowSize(float shadowSize, float maxShadowSize) {
        if (shadowSize >= 0.0F && maxShadowSize >= 0.0F) {
            shadowSize = (float)toEven(shadowSize);
            maxShadowSize = (float)toEven(maxShadowSize);
            if (shadowSize > maxShadowSize) {
                shadowSize = maxShadowSize;
                if (!this.printedShadowClipWarning) {
                    this.printedShadowClipWarning = true;
                }
            }
    
            if (this.rawShadowSize != shadowSize || this.rawMaxShadowSize != maxShadowSize) {
                this.rawShadowSize = shadowSize;
                this.rawMaxShadowSize = maxShadowSize;
                this.shadowSize = (float)Math.round(shadowSize * 1.5F);
                this.maxShadowSize = maxShadowSize;
                this.dirty = true;
                this.invalidateSelf();
            }
        } else {
            throw new IllegalArgumentException("invalid shadow size");
        }
    }
    
    public void setShadowSize(float size) {
        this.setShadowSize(size, this.rawMaxShadowSize);
    }
    
    public float getShadowSize() {
        return this.rawShadowSize;
    }
    
    public boolean getPadding(Rect padding) {
        int vOffset = (int)Math.ceil((double)calculateVerticalPadding(this.rawMaxShadowSize, this.cornerRadius, this.addPaddingForCorners));
        int hOffset = (int)Math.ceil((double)calculateHorizontalPadding(this.rawMaxShadowSize, this.cornerRadius, this.addPaddingForCorners));
        padding.set(hOffset, vOffset, hOffset, vOffset);
        return true;
    }
    
    public static float calculateVerticalPadding(float maxShadowSize, float cornerRadius, boolean addPaddingForCorners) {
        return addPaddingForCorners ? (float)((double)(maxShadowSize * 1.5F) + (1.0D - COS_45) * (double)cornerRadius) : maxShadowSize * 1.5F;
    }
    
    public static float calculateHorizontalPadding(float maxShadowSize, float cornerRadius, boolean addPaddingForCorners) {
        return addPaddingForCorners ? (float)((double)maxShadowSize + (1.0D - COS_45) * (double)cornerRadius) : maxShadowSize;
    }
    
    public int getOpacity() {
        return -3;
    }
    
    public void setCornerRadius(float radius) {
        radius = (float)Math.round(radius);
        if (this.cornerRadius != radius) {
            this.cornerRadius = radius;
            this.dirty = true;
            this.invalidateSelf();
        }
    }
    
    public void draw(Canvas canvas) {
        if (this.dirty) {
            this.buildComponents(this.getBounds());
            this.dirty = false;
        }
    
        this.drawShadow(canvas);
        super.draw(canvas);
    }
    
    public final void setRotation(float rotation) {
        if (this.rotation != rotation) {
            this.rotation = rotation;
            this.invalidateSelf();
        }
    
    }
    
    private void drawShadow(Canvas canvas) {
        int rotateSaved = canvas.save();
        canvas.rotate(this.rotation, this.contentBounds.centerX(), this.contentBounds.centerY());
        float edgeShadowTop = -this.cornerRadius - this.shadowSize;
        float shadowOffset = this.cornerRadius;
        boolean drawHorizontalEdges = this.contentBounds.width() - 2.0F * shadowOffset > 0.0F;
        boolean drawVerticalEdges = this.contentBounds.height() - 2.0F * shadowOffset > 0.0F;
        float shadowOffsetTop = this.rawShadowSize - this.rawShadowSize * 0.25F;
        float shadowOffsetHorizontal = this.rawShadowSize - this.rawShadowSize * 0.5F;
        float shadowOffsetBottom = this.rawShadowSize - this.rawShadowSize * 1.0F;
        float shadowScaleHorizontal = shadowOffset / (shadowOffset + shadowOffsetHorizontal);
        float shadowScaleTop = shadowOffset / (shadowOffset + shadowOffsetTop);
        float shadowScaleBottom = shadowOffset / (shadowOffset + shadowOffsetBottom);
        int saved = canvas.save();
        canvas.translate(this.contentBounds.left + shadowOffset, this.contentBounds.top + shadowOffset);
        canvas.scale(shadowScaleHorizontal, shadowScaleTop);
        canvas.drawPath(this.cornerShadowPath, this.cornerShadowPaint);
        if (drawHorizontalEdges) {
            canvas.scale(1.0F / shadowScaleHorizontal, 1.0F);
            canvas.drawRect(0.0F, edgeShadowTop, this.contentBounds.width() - 2.0F * shadowOffset, -this.cornerRadius, this.edgeShadowPaint);
        }
    
        canvas.restoreToCount(saved);
        saved = canvas.save();
        canvas.translate(this.contentBounds.right - shadowOffset, this.contentBounds.bottom - shadowOffset);
        canvas.scale(shadowScaleHorizontal, shadowScaleBottom);
        canvas.rotate(180.0F);
        canvas.drawPath(this.cornerShadowPath, this.cornerShadowPaint);
        if (drawHorizontalEdges) {
            canvas.scale(1.0F / shadowScaleHorizontal, 1.0F);
            canvas.drawRect(0.0F, edgeShadowTop, this.contentBounds.width() - 2.0F * shadowOffset, -this.cornerRadius + this.shadowSize, this.edgeShadowPaint);
        }
    
        canvas.restoreToCount(saved);
        saved = canvas.save();
        canvas.translate(this.contentBounds.left + shadowOffset, this.contentBounds.bottom - shadowOffset);
        canvas.scale(shadowScaleHorizontal, shadowScaleBottom);
        canvas.rotate(270.0F);
        canvas.drawPath(this.cornerShadowPath, this.cornerShadowPaint);
        if (drawVerticalEdges) {
            canvas.scale(1.0F / shadowScaleBottom, 1.0F);
            canvas.drawRect(0.0F, edgeShadowTop, this.contentBounds.height() - 2.0F * shadowOffset, -this.cornerRadius, this.edgeShadowPaint);
        }
    
        canvas.restoreToCount(saved);
        saved = canvas.save();
        canvas.translate(this.contentBounds.right - shadowOffset, this.contentBounds.top + shadowOffset);
        canvas.scale(shadowScaleHorizontal, shadowScaleTop);
        canvas.rotate(90.0F);
        canvas.drawPath(this.cornerShadowPath, this.cornerShadowPaint);
        if (drawVerticalEdges) {
            canvas.scale(1.0F / shadowScaleTop, 1.0F);
            canvas.drawRect(0.0F, edgeShadowTop, this.contentBounds.height() - 2.0F * shadowOffset, -this.cornerRadius, this.edgeShadowPaint);
        }
    
        canvas.restoreToCount(saved);
        canvas.restoreToCount(rotateSaved);
    }
    
    private void buildShadowCorners() {
        RectF innerBounds = new RectF(-this.cornerRadius, -this.cornerRadius, this.cornerRadius, this.cornerRadius);
        RectF outerBounds = new RectF(innerBounds);
        outerBounds.inset(-this.shadowSize, -this.shadowSize);
        if (this.cornerShadowPath == null) {
            this.cornerShadowPath = new Path();
        } else {
            this.cornerShadowPath.reset();
        }
    
        this.cornerShadowPath.setFillType(Path.FillType.EVEN_ODD);
        this.cornerShadowPath.moveTo(-this.cornerRadius, 0.0F);
        this.cornerShadowPath.rLineTo(-this.shadowSize, 0.0F);
        this.cornerShadowPath.arcTo(outerBounds, 180.0F, 90.0F, false);
        this.cornerShadowPath.arcTo(innerBounds, 270.0F, -90.0F, false);
        this.cornerShadowPath.close();
        float shadowRadius = -outerBounds.top;
        if (shadowRadius > 0.0F) {
            float startRatio = this.cornerRadius / shadowRadius;
            float midRatio = startRatio + (1.0F - startRatio) / 2.0F;
            this.cornerShadowPaint.setShader(new RadialGradient(0.0F, 0.0F, shadowRadius, new int[]{0, this.shadowStartColor, this.shadowMiddleColor, this.shadowEndColor}, new float[]{0.0F, startRatio, midRatio, 1.0F}, Shader.TileMode.CLAMP));
        }
    
        this.edgeShadowPaint.setShader(new LinearGradient(0.0F, innerBounds.top, 0.0F, outerBounds.top, new int[]{this.shadowStartColor, this.shadowMiddleColor, this.shadowEndColor}, new float[]{0.0F, 0.5F, 1.0F}, Shader.TileMode.CLAMP));
        this.edgeShadowPaint.setAntiAlias(false);
    }
    
    private void buildComponents(Rect bounds) {
        float verticalOffset = this.rawMaxShadowSize * 1.5F;
        this.contentBounds.set((float)bounds.left + this.rawMaxShadowSize, (float)bounds.top + verticalOffset, (float)bounds.right - this.rawMaxShadowSize, (float)bounds.bottom - verticalOffset);
        this.getWrappedDrawable().setBounds((int)this.contentBounds.left, (int)this.contentBounds.top, (int)this.contentBounds.right, (int)this.contentBounds.bottom);
        this.buildShadowCorners();
    }
    
    public float getCornerRadius() {
        return this.cornerRadius;
    }
    
    public void setMaxShadowSize(float size) {
        this.setShadowSize(this.rawShadowSize, size);
    }
    
    public float getMaxShadowSize() {
        return this.rawMaxShadowSize;
    }
    
    public float getMinWidth() {
        float content = 2.0F * Math.max(this.rawMaxShadowSize, this.cornerRadius + this.rawMaxShadowSize / 2.0F);
        return content + this.rawMaxShadowSize * 2.0F;
    }
    
    public float getMinHeight() {
        float content = 2.0F * Math.max(this.rawMaxShadowSize, this.cornerRadius + this.rawMaxShadowSize * 1.5F / 2.0F);
        return content + this.rawMaxShadowSize * 1.5F * 2.0F;
    }
    

    }

    DrawableWrapper源码:

    @RestrictTo({RestrictTo.Scope.LIBRARY_GROUP})
    public class DrawableWrapper extends Drawable implements Drawable.Callback {
    private Drawable mDrawable;

    public DrawableWrapper(Drawable drawable) {
        this.setWrappedDrawable(drawable);
    }
    
    public void draw(Canvas canvas) {
        this.mDrawable.draw(canvas);
    }
    
    protected void onBoundsChange(Rect bounds) {
        this.mDrawable.setBounds(bounds);
    }
    
    public void setChangingConfigurations(int configs) {
        this.mDrawable.setChangingConfigurations(configs);
    }
    
    public int getChangingConfigurations() {
        return this.mDrawable.getChangingConfigurations();
    }
    
    public void setDither(boolean dither) {
        this.mDrawable.setDither(dither);
    }
    
    public void setFilterBitmap(boolean filter) {
        this.mDrawable.setFilterBitmap(filter);
    }
    
    public void setAlpha(int alpha) {
        this.mDrawable.setAlpha(alpha);
    }
    
    public void setColorFilter(ColorFilter cf) {
        this.mDrawable.setColorFilter(cf);
    }
    
    public boolean isStateful() {
        return this.mDrawable.isStateful();
    }
    
    public boolean setState(int[] stateSet) {
        return this.mDrawable.setState(stateSet);
    }
    
    public int[] getState() {
        return this.mDrawable.getState();
    }
    
    public void jumpToCurrentState() {
        DrawableCompat.jumpToCurrentState(this.mDrawable);
    }
    
    public Drawable getCurrent() {
        return this.mDrawable.getCurrent();
    }
    
    public boolean setVisible(boolean visible, boolean restart) {
        return super.setVisible(visible, restart) || this.mDrawable.setVisible(visible, restart);
    }
    
    public int getOpacity() {
        return this.mDrawable.getOpacity();
    }
    
    public Region getTransparentRegion() {
        return this.mDrawable.getTransparentRegion();
    }
    
    public int getIntrinsicWidth() {
        return this.mDrawable.getIntrinsicWidth();
    }
    
    public int getIntrinsicHeight() {
        return this.mDrawable.getIntrinsicHeight();
    }
    
    public int getMinimumWidth() {
        return this.mDrawable.getMinimumWidth();
    }
    
    public int getMinimumHeight() {
        return this.mDrawable.getMinimumHeight();
    }
    
    public boolean getPadding(Rect padding) {
        return this.mDrawable.getPadding(padding);
    }
    
    public void invalidateDrawable(Drawable who) {
        this.invalidateSelf();
    }
    
    public void scheduleDrawable(Drawable who, Runnable what, long when) {
        this.scheduleSelf(what, when);
    }
    
    public void unscheduleDrawable(Drawable who, Runnable what) {
        this.unscheduleSelf(what);
    }
    
    protected boolean onLevelChange(int level) {
        return this.mDrawable.setLevel(level);
    }
    
    public void setAutoMirrored(boolean mirrored) {
        DrawableCompat.setAutoMirrored(this.mDrawable, mirrored);
    }
    
    public boolean isAutoMirrored() {
        return DrawableCompat.isAutoMirrored(this.mDrawable);
    }
    
    public void setTint(int tint) {
        DrawableCompat.setTint(this.mDrawable, tint);
    }
    
    public void setTintList(ColorStateList tint) {
        DrawableCompat.setTintList(this.mDrawable, tint);
    }
    
    public void setTintMode(PorterDuff.Mode tintMode) {
        DrawableCompat.setTintMode(this.mDrawable, tintMode);
    }
    
    public void setHotspot(float x, float y) {
        DrawableCompat.setHotspot(this.mDrawable, x, y);
    }
    
    public void setHotspotBounds(int left, int top, int right, int bottom) {
        DrawableCompat.setHotspotBounds(this.mDrawable, left, top, right, bottom);
    }
    
    public Drawable getWrappedDrawable() {
        return this.mDrawable;
    }
    
    public void setWrappedDrawable(Drawable drawable) {
        if (this.mDrawable != null) {
            this.mDrawable.setCallback((Callback)null);
        }
    
        this.mDrawable = drawable;
        if (drawable != null) {
            drawable.setCallback(this);
        }
    
    }
    

    }

    相关文章

      网友评论

          本文标题:偷用FloatActionButton的源码实现可更改颜色的阴影

          本文链接:https://www.haomeiwen.com/subject/iwezvctx.html