一泡态、需求來(lái)源:
設(shè)計(jì)師要求還原設(shè)計(jì)的陰影苦囱,下面是sketch原型參數(shù):
圓角:8px
外陰影:
Offset: 0px 1px
X Y
Effect: 10px 0px
Blur Spread
顏色: #135B90D0
二疚宇、Android本身控件自帶陰影效果無(wú)法還原
Google的Material Design中對(duì)于陰影的定義是:海拔高度是相對(duì)深度或距離籽腕,是兩個(gè)表面在 Z 軸上的距離乾蓬。
實(shí)現(xiàn)方式:
第一種方式:elevation屬性
View的大小位置都是通過(guò)x,y確定的渊抄,而現(xiàn)在有了z軸的概念尝胆,而這個(gè)z值就是View的高度(elevation)丧裁,而高度決定了陰影(shadow)的大小护桦。第二種方式:CardView自帶屬性
card_view:cardElevation 陰影的大小
card_view:cardMaxElevation 陰影最大高度
card_view:cardBackgroundColor 卡片的背景色
card_view:cardCornerRadius 卡片的圓角大小
card_view:contentPadding 卡片內(nèi)容于邊距的間隔
- 第三種方式:
設(shè)置邊框?yàn)閟hape,通過(guò)layer-list實(shí)現(xiàn)層次感
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="oval">
<padding
android:bottom="2dp"
android:left="2dp"
android:right="2dp"
android:top="2dp" />
<solid android:color="#0DF3F3F3" />
<corners android:radius="8dp" />
</shape>
</item>
<item>
<shape
android:layout_width="wrap_content"
android:shape="oval">
<padding
android:bottom="2dp"
android:left="2dp"
android:right="2dp"
android:top="2dp" />
<solid android:color="#10F3F3F3" />
<corners android:radius="8dp" />
</shape>
</item>
<item>
<shape android:shape="oval">
<padding
android:bottom="2dp"
android:left="2dp"
android:right="2dp"
android:top="2dp" />
<solid android:color="#15F3F3F3" />
<corners android:radius="8dp" />
</shape>
</item>
<item>
<shape android:shape="oval">
<padding
android:bottom="2dp"
android:left="2dp"
android:right="2dp"
android:top="2dp" />
<solid android:color="#20F3F3F3" />
<corners android:radius="8dp" />
</shape>
</item>
<item>
<shape android:shape="oval">
<padding
android:bottom="2dp"
android:left="2dp"
android:right="2dp"
android:top="2dp" />
<solid android:color="#25F3F3F3" />
<corners android:radius="8dp" />
</shape>
</item>
<item>
<shape android:shape="oval">
<solid android:color="#FFFFFF" />
</shape>
</item>
</layer-list>
三煎娇、使用Android畫筆Paint來(lái)實(shí)現(xiàn)
- 第四種方式(屬性一一對(duì)應(yīng)設(shè)計(jì)稿):
/**
* 使用圓角時(shí)二庵,應(yīng)設(shè)置圓角相同的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); // 關(guān)閉硬件加速,陰影才會(huì)繪制
// todo 從AttributeSet獲取設(shè)置的值
mPaint.setAntiAlias(true);
mPaint.setColor(shadowColor);
mPaint.setMaskFilter(new BlurMaskFilter(shadowBlur, BlurMaskFilter.Blur.NORMAL));
}
@Override
public boolean isOpaque() { //純色或圖片做背景時(shí),draw之前會(huì)有黑底色缓呛,
return false;
}
}
attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="ShadowRelativeLayout">
<attr format="color" name="shadow_color"/>
<attr format="dimension" name="shadow_radius"/>
<attr format="dimension" name="shadow_blur"/>
<attr format="dimension" name="shadow_dx"/>
<attr format="dimension" name="shadow_dy"/>
</declare-styleable>
</resources>
使用范例(屬性完美映射設(shè)計(jì)稿):
<ShadowRelativeLayout
android:layout_width="180dp"
android:layout_height="100dp"
android:background="@drawable/shape_round_white_dp8"
android:padding="10dp"
bind:shadow_blur="10dp"
bind:shadow_color="#135B90D0"
bind:shadow_dx="0dp"
bind:shadow_dy="1dp"
bind:shadow_radius="8dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_gravity="center"
android:scaleType="center"
android:src="@drawable/light" />
</ShadowRelativeLayout>