Android 有很多的设计是有阴影效果的,基于此谢了这篇文章:

我们先来看看实现的效果:

背景

随着这几年UI风格的不断升级,阴影已经成了很多APP设计中的不可或缺的元素。但Android在这方面却没有比较好的实现方式。
这里有总结的一篇关于Android阴影效果的文章,比较全面,值得一看。聊聊 Material Design 里,阴影的那些事儿!
上面这篇文章对Android中各版本的阴影实现都进行了说明,这里就不再细说了。虽然提供的方式很多,但是却有很大的局限性,具体表现在以下两方面:
无法改变阴影的颜色;
存在兼容性问题;
虽然也可以按照作者提供的方式,使用Fab或CardView实现阴影的原理来实现,但相对比较麻烦,这里我们提供一个简单的实现方案。
实现思想
为View添加阴影,其实就是为View提供一个有阴影的背景而已,所以有2中实现方式:
重写View的onDraw()方法;
自定义Drawable;
第一种明显不合理,我们不可能重写每个需要设置阴影的View的onDraw(),所以这里选择自定义Drwable(通过设置Paint的ShadowLayer)来实现。需要注意的是:这种方式实现的阴影,其目标View需要关闭硬件加速。

view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

需求点

  • 可设置阴影颜色,圆角,面积,偏移量;

  • 可设置View的背景形状,颜色,圆角;

实现

源码地址:ShadeDrawable

public class ShadowDrawable extends Drawable { private Paint mPaint; private int mShadowRadius;  // 阴影圆角 private int mShape;         // 背景形状 private int mShapeRadius;   // 背景圆角 private int mOffsetX;       // 阴影的水平偏移量 private int mOffsetY;       // 阴影的垂直偏移量 private int mBgColor[];     // 背景颜色 private RectF mRect; public final static int SHAPE_ROUND = 1;    // 表示圆角矩形 public final static int SHAPE_CIRCLE = 2;   // 表示圆 private ShadowDrawable(int shape, int[] bgColor, int shapeRadius, int shadowColor, int shadowRadius, int offsetX, int offsetY) {   this.mShape = shape;   this.mBgColor = bgColor;   this.mShapeRadius = shapeRadius;   this.mShadowRadius = shadowRadius;   this.mOffsetX = offsetX;   this.mOffsetY = offsetY;   mPaint = new Paint();   mPaint.setColor(Color.TRANSPARENT);   mPaint.setAntiAlias(true);   mPaint.setShadowLayer(shadowRadius, offsetX, offsetY, shadowColor);     mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP)); } @Override public void setBounds(int left, int top, int right, int bottom) {   super.setBounds(left, top, right, bottom);   mRect = new RectF(left + mShadowRadius - mOffsetX, top + mShadowRadius - mOffsetY, right - mShadowRadius - mOffsetX,       bottom - mShadowRadius - mOffsetY); } @Override public void draw(@NonNull Canvas canvas) {   if (mShape == SHAPE_ROUND) {     canvas.drawRoundRect(mRect, mShapeRadius, mShapeRadius, mPaint);     Paint newPaint = new Paint();     if (mBgColor != null) {       if (mBgColor.length == 1) {         newPaint.setColor(mBgColor[0]);       } else {         newPaint.setShader(new LinearGradient(mRect.left, mRect.height() / 2, mRect.right, mRect.height() / 2, mBgColor,             null, Shader.TileMode.CLAMP));       }     }     newPaint.setAntiAlias(true);     canvas.drawRoundRect(mRect, mShapeRadius, mShapeRadius, newPaint);   } else {     canvas.drawCircle(mRect.centerX(), mRect.centerY(), Math.min(mRect.width(), mRect.height())/ 2, mPaint);   } } @Override public void setAlpha(int alpha) {   mPaint.setAlpha(alpha); } @Override public void setColorFilter(@Nullable ColorFilter colorFilter) {   mPaint.setColorFilter(colorFilter); } @Override public int getOpacity() {   return PixelFormat.TRANSLUCENT; }}

由于提供的属性比较多,为了便于使用,提供了Builder的链式创建方式,同时提供了常用的几个static方法,设置阴影只需一行代码即可,具体查看ShadowDrawable.java。

public static void setShadowDrawable(View view, int shapeRadius, int shadowColor, int shadowRadius, int offsetX, int offsetY) { ShadowDrawable drawable = new ShadowDrawable.Builder()     .setShapeRadius(shapeRadius)     .setShadowColor(shadowColor)     .setShadowRadius(shadowRadius)     .setOffsetX(offsetX)     .setOffsetY(offsetY)     .builder(); view.setLayerType(View.LAYER_TYPE_SOFTWARE, null); ViewCompat.setBackground(view, drawable);}

实例效果

注意点

设置阴影的颜色时,需要带有透明度(即”#XXXXXXXX”的形式,如50%的黑色[“#80000000”]),而不能使用纯色;
上面提供的这种实现方式,阴影部分总是作为View的一部分而存在的,所以在使用时,需要为阴影留出相对应的padding, 才会让阴影显示出来;

总结

由于Android系统并没有提供完美的解决方案,即便使用5.0以上提供的elevation或translationZ属性,对于大面积的阴影,看起来也比较生硬, 所以在Android开发中,对于阴影的处理,还是应该分情况来对待,大面积的阴影强烈推荐使用9Patch图来解决,对于小控件的阴影,可使用以上的方案。

作者:tinycoder
转载自:https://juejin.im/post/5ae1ba4d6fb9a07acc116b8d


如果觉得写得好,扫码关注一下点个赞,是我最大的动力。

关注我,一定会有意想不到的东西等着你:
每天专注分享Android、JAVA干货

备注:程序圈LT

更多相关文章

  1. 浅谈Java中Collections.sort对List排序的两种方法
  2. python list.sort()根据多个关键字排序的方法实现
  3. Android之AIDL实现两个app的调用以及双进程app的进程通信
  4. Android简单语音控制应用的实现
  5. Android(安卓)Push Notification技术实现
  6. Android(安卓)滑动效果高级篇(七)—— 华丽翻页效果
  7. Android与设计模式浅谈
  8. Android的多媒体框架OpenCore(PacketVideo)介绍
  9. 基于Android(安卓)Bionic 库动态编译busybox

随机推荐

  1. 【android】为PopupWindow设置动画效果
  2. lighting sensor 部分分析
  3. ios开发答疑录系列​---(一)Android和IOS
  4. UNEXPECTED TOP-LEVEL EXCEPTION 处理
  5. 获取高德key
  6. android 抓包实际应用
  7. Android(安卓)Http请求方法汇总
  8. SharedPerferences的使用
  9. [Android] Android(安卓)sqlite事务
  10. iOS-SwiftMonkey测试