一、需求来源:
设计师要求还原设计的阴影,下面是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
使用范例(属性完美映射设计稿):