Android阴影背景的实现

一、需求来源:

设计师要求还原设计的阴影,下面是sketch原型参数:

圆角:8px

外阴影:                    
Offset:     0px     1px                         
             X       Y              

Effect:     10px    0px                 
            Blur    Spread                  

颜色:      #135B90D0                       

二、Android本身控件自带阴影效果无法还原

Google的Material Design中对于阴影的定义是:海拔高度是相对深度或距离,是两个表面在 Z 轴上的距离。

实现方式:

  • 第一种方式:elevation属性
    View的大小位置都是通过x,y确定的,而现在有了z轴的概念,而这个z值就是View的高度(elevation),而高度决定了阴影(shadow)的大小。

  • 第二种方式:CardView自带属性

card_view:cardElevation 阴影的大小
card_view:cardMaxElevation 阴影最大高度
card_view:cardBackgroundColor 卡片的背景色
card_view:cardCornerRadius 卡片的圆角大小
card_view:contentPadding 卡片内容于边距的间隔
  • 第三种方式:
    设置边框为shape,通过layer-list实现层次感


    
        
        
        
    

    
        
            
            
            
        
    

    
        
        
        
    


    
        
        
        
    


    
        
        
        
    


    
        
    


三、使用Android画笔Paint来实现

  • 第四种方式(属性一一对应设计稿):
/**
 * 使用圆角时,应设置圆角相同的background
 */

public class ShadowRelativeLayout extends RelativeLayout {
    /**
     * 阴影的颜色
     */
    private int shadowColor = Color.argb(90, 0, 0, 0);
    /**
     * 高斯模糊的模糊半径,值越大越模糊,越小越清晰,
     */
    private float shadowBlur = 30;
    /**
     * 阴影的圆角
     */
    private float shadowRadius = 0;

    /**
     * 阴影的偏移
     */
    private float shadowDx = 0;
    private float shadowDy = 0;

    public ShadowRelativeLayout(@NonNull Context context) {
        this(context, null);
    }

    public ShadowRelativeLayout(@NonNull Context context,
                                @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ShadowRelativeLayout(@NonNull Context context, @Nullable AttributeSet attrs,
                                int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        dealAttrs(context, attrs);
        setPaint();
    }

    private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

    @Override
    public void draw(Canvas canvas) {
        setInsetBackground();
        canvas.drawRoundRect(getRectF(), shadowRadius, shadowRadius, mPaint);
        super.draw(canvas);
    }

    private boolean setInsetBackground() {
        Drawable background = getBackground();
        if (background == null || background instanceof InsetDrawable) {
            return false;
        }
        InsetDrawable drawable =
                new InsetDrawable(background, getPaddingLeft(), getPaddingTop(),
                        getPaddingRight(), getPaddingBottom());
        setBackground(drawable);
        return true;
    }

    private RectF getRectF() {
        return new RectF(getPaddingLeft() + shadowDx, getPaddingTop() + shadowDy,
                getWidth() - getPaddingRight() + shadowDx,
                getHeight() - getPaddingBottom() + shadowDy);
    }

    private void dealAttrs(Context context, AttributeSet attrs) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ShadowRelativeLayout);
        if (typedArray != null) {
            shadowColor = typedArray.getColor(R.styleable.ShadowRelativeLayout_shadow_color, shadowColor);
            shadowRadius =
                    typedArray.getDimension(R.styleable.ShadowRelativeLayout_shadow_radius, shadowRadius);
            shadowBlur =
                    typedArray.getDimension(R.styleable.ShadowRelativeLayout_shadow_blur, shadowBlur);
            shadowDx = typedArray.getDimension(R.styleable.ShadowRelativeLayout_shadow_dx, shadowDx);
            shadowDy = typedArray.getDimension(R.styleable.ShadowRelativeLayout_shadow_dy, shadowDy);
            typedArray.recycle();
        }
    }

    private void setPaint() {
        setLayerType(View.LAYER_TYPE_SOFTWARE, null);  // 关闭硬件加速,阴影才会绘制
        // todo 从AttributeSet获取设置的值
        mPaint.setAntiAlias(true);
        mPaint.setColor(shadowColor);
        mPaint.setMaskFilter(new BlurMaskFilter(shadowBlur, BlurMaskFilter.Blur.NORMAL));
    }

    @Override
    public boolean isOpaque() { //纯色或图片做背景时,draw之前会有黑底色,
        return false;
    }
}

attrs.xml



    
        
        
        
        
        
    

使用范例(属性完美映射设计稿):


    


你可能感兴趣的:(Android阴影背景的实现)