<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!--底层的左边距离上层左边3dp, 底层的顶部,距离上层的顶部6dp,如果不做这个控制,底层和上层的左侧和上侧会重合在一起-->
<item android:left="3dp"
android:top="6dp">
<shape>
<solid android:color="#b4b5b6"/>
</shape>
</item>
<!--上层的右边距离底层的右边3dp, 上层的底部距离底层的底部6dp-->
<item android:bottom="6dp"
android:right="3dp">
<shape>
<solid android:color="#fff"/>
</shape>
</item>
</layer-list>
shadowDX、shadowDy、shadowRadius,分别指的是阴影的横、纵坐标偏移,以及阴影的半径,
如果是TextView可以直接在布局中设置:
<TextView
android:id="@+id/test_shadow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="60sp"
android:textColor="#cc000000"
android:text="Test Shadow"
android:layout_gravity="center"
android:shadowColor="#aa22ff22"
android:shadowRadius="10"
android:shadowDx="0"
android:shadowDy="0"
/>
<TextView
android:id="@+id/btn_test_performance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:elevation="5dp"
android:text="@string/hello"
android:background="@drawable/shape_round_white"
android:padding="20dp"
android:layout_marginTop="10dp"
android:layout_gravity="center"/>
这种方式有个局限性, 那就是api25以上才能显示出来
/**
* ShadowLayout.java
* <p>
* Created by lijiankun on 17/8/11.
*/
public class ShadowLayout extends RelativeLayout {
public static final int ALL = 0x1111;
public static final int LEFT = 0x0001;
public static final int TOP = 0x0010;
public static final int RIGHT = 0x0100;
public static final int BOTTOM = 0x1000;
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private RectF mRectF = new RectF();
/**
* 阴影的颜色
*/
private int mShadowColor = Color.TRANSPARENT;
/**
* 阴影的大小范围
*/
private float mShadowRadius = 0;
/**
* 阴影 x 轴的偏移量
*/
private float mShadowDx = 0;
/**
* 阴影 y 轴的偏移量
*/
private float mShadowDy = 0;
/**
* 阴影显示的边界
*/
private int mShadowSide = ALL;
public ShadowLayout(Context context) {
this(context, null);
}
public ShadowLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public ShadowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs);
}
/**
* 获取绘制阴影的位置,并为 ShadowLayout 设置 Padding 以为显示阴影留出空间
*/
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
float effect = mShadowRadius + dip2px(5);
float rectLeft = 0;
float rectTop = 0;
float rectRight = this.getWidth();
float rectBottom = this.getHeight();
int paddingLeft = 0;
int paddingTop = 0;
int paddingRight = 0;
int paddingBottom = 0;
if (((mShadowSide & LEFT) == LEFT)) {
rectLeft = effect;
paddingLeft = (int) effect;
}
if (((mShadowSide & TOP) == TOP)) {
rectTop = effect;
paddingTop = (int) effect;
}
if (((mShadowSide & RIGHT) == RIGHT)) {
rectRight = this.getWidth() - effect;
paddingRight = (int) effect;
}
if (((mShadowSide & BOTTOM) == BOTTOM)) {
rectBottom = this.getHeight() - effect;
paddingBottom = (int) effect;
}
if (mShadowDy != 0.0f) {
rectBottom = rectBottom - mShadowDy;
paddingBottom = paddingBottom + (int) mShadowDy;
}
if (mShadowDx != 0.0f) {
rectRight = rectRight - mShadowDx;
paddingRight = paddingRight + (int) mShadowDx;
}
mRectF.left = rectLeft;
mRectF.top = rectTop;
mRectF.right = rectRight;
mRectF.bottom = rectBottom;
this.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
}
/**
* 真正绘制阴影的方法
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawRect(mRectF, mPaint);
}
/**
* 读取设置的阴影的属性
*
* @param attrs 从其中获取设置的值
*/
private void init(AttributeSet attrs) {
setLayerType(View.LAYER_TYPE_SOFTWARE, null); // 关闭硬件加速
this.setWillNotDraw(false); // 调用此方法后,才会执行 onDraw(Canvas) 方法
TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.ShadowLayout);
if (typedArray != null) {
mShadowColor = typedArray.getColor(R.styleable.ShadowLayout_shadowColor,
ContextCompat.getColor(getContext(), android.R.color.black));
mShadowRadius = typedArray.getDimension(R.styleable.ShadowLayout_shadowRadius, dip2px(0));
mShadowDx = typedArray.getDimension(R.styleable.ShadowLayout_shadowDx, dip2px(0));
mShadowDy = typedArray.getDimension(R.styleable.ShadowLayout_shadowDy, dip2px(0));
mShadowSide = typedArray.getInt(R.styleable.ShadowLayout_shadowSide, ALL);
typedArray.recycle();
}
mPaint.setAntiAlias(true);
mPaint.setColor(Color.TRANSPARENT);
mPaint.setShadowLayer(mShadowRadius, mShadowDx, mShadowDy, mShadowColor);
}
/**
* dip2px dp 值转 px 值
*
* @param dpValue dp 值
* @return px 值
*/
private float dip2px(float dpValue) {
DisplayMetrics dm = getContext().getResources().getDisplayMetrics();
float scale = dm.density;
return (dpValue * scale + 0.5F);
}
}
属性文件:
<declare-styleable name="ShadowLayout">
<attr name="shadowColor" format="color"/>
<attr name="shadowRadius" format="dimension"/>
<attr name="shadowDx" format="dimension"/>
<attr name="shadowDy" format="dimension"/>
<attr name="shadowSide" format="integer"/>
</declare-styleable>
该种方式定制性强, 兼容性好, 需要注意的是避免将9patch宽高设置过大 小图可以拉大 大图不方便缩小
链接地址:http://inloop.github.io/shadow4android/