记录一下使用cardView来实现阴影效果时碰到的版本适配的解决方案。

一、背景

在API 21以前想要实现阴影效果一般要通过drawable或者.9图去手动实现,随着Material Design的出现,阴影效果也开始得到官方支持,这个时候使用android:elevation和android:translateZ可以很方便的实现阴影效果,同时也出现了CardView和FloatingActionButton这些自带阴影效果的support控件。

这里是一些使用过程中优缺点的体会:

  1. 使用drawable或者.9图,优点是不用但心适配问题,不同API版本会有一致的效果,实现也相对简单。
    缺点主要是阴影效果相对来说还是有些僵硬,不如API21以上系统的阴影自然,其次是没有Z轴的概念。
                                                                                                
Drawable阴影效果
  1. 使用android:elevation和android:translateZ,这个优缺点很明显了,优点简单且效果好,缺点是只支持API21以上,而且support库也没有提供支持,ViewCompat中有相应的方法但是在api21以下并没有做任何处理。

  2. 使用CardView或者FloatingActionButton这些自带阴影的控件。优点是阴影效果好且支持低版本。
    缺点则是API 21以上和以下的版本可能会有不同的视觉效果,比如简单的使用如下代码效果如图所示:

                                    
左边API19,右边API22

二、CardView的阴影效果原理

//CardView的静态代码static {        if (Build.VERSION.SDK_INT >= 21) {            IMPL = new CardViewApi21Impl();        } else if (Build.VERSION.SDK_INT >= 17) {            IMPL = new CardViewApi17Impl();        } else {            IMPL = new CardViewBaseImpl();        }        IMPL.initStatic();    }

cardView针对不同的API做了不同的处理,简单的看下实现原理如下

    //CardViewApi21Impl 的初始化方法    @Override    public void initialize(CardViewDelegate cardView, Context context,                ColorStateList backgroundColor, float radius, float elevation, float maxElevation) {        final RoundRectDrawable background = new RoundRectDrawable(backgroundColor, radius);        cardView.setCardBackground(background);        View view = cardView.getCardView();        view.setClipToOutline(true);        //通过setElevation属性实现阴影        view.setElevation(elevation);        setMaxElevation(cardView, maxElevation);    }
    //CardViewApi17Impl    @Override    public void initStatic() {        RoundRectDrawableWithShadow.sRoundRectHelper =                new RoundRectDrawableWithShadow.RoundRectHelper() {                    @Override                    public void drawRoundRect(Canvas canvas, RectF bounds, float cornerRadius,                            Paint paint) {                        canvas.drawRoundRect(bounds, cornerRadius, cornerRadius, paint);                    }                };    }

可以看到API21以上仍然使用系统的elevation属性。API21以下则通过canvas.drawRoundRect实现,具体的细节在RoundRectDrawableWithShadow这个Drawable中,这个类用来绘制一个带阴影的矩形,来作为CardView的background。

 //CardViewBaseImpl RoundRectDrawableWithShadow background = createBackground(context,   backgroundColor, radius, elevation, maxElevation); background.setAddPaddingForCorners(cardView.getPreventCornerOverlap()); cardView.setCardBackground(background); updatePadding(cardView);

三、问题与解决方案

如上面效果图所示,可以看到不同API效果差别还是比较大的。

  1. 阴影效果不明显。
    可以通过app:cardElevation调节阴影效果。

  2. 如上面效果所示,本来该悬浮在CardView之上的控件显示在了下面。
    这从侧面也可以验证CardViewAPI21以上是通过Z轴来改变的,这个时候给要悬浮其上的添加Android:elevation属性即可保证一致的视觉效果。

  3. cardView外层嵌套布局后API21以上阴影效果失效。
    添加app:cardUseCompatPadding="true"属性。

  4. 添加完cardUseCompatPadding发现cardView的width和height改变了。
    我们知道通过drawable添加阴影,阴影会占为控件的一部分,设置cardUseCompatPadding为true后无论哪个API版本,阴影都会占控件的一部分,这个时候就要自己去处理边距问题了,预留一部分空间。

  5. CardView如果设置了圆角,低版本会出现margin。
    添加app:cardPreventCornerOverlap="false",使内容和圆角重叠,覆盖圆角。默认是true。

左边API19,右边API22

更多相关文章

  1. 【Android(安卓)开发】:Android布局中的几种常用属性
  2. Android对SlidingDraw组件修改
  3. Android(安卓)UI控件之RadioGroup、RadioButton
  4. Android(安卓)中的ellipsize
  5. Android(安卓)Notification 用法的4种形式
  6. Android软件开发常用系统控件(一) TextView
  7. 第十四周实验报告:实验四 Android程序设计
  8. android基础控件学习学习(1)【入门篇】
  9. 桌面小控件(Widget)--之清理进程

随机推荐

  1. android 上传项目到Github
  2. [置顶] Android 内存泄漏
  3. 从CM刷机过程和原理分析Android系统结构
  4. android 监听网络状态的变化及实战
  5. Android(4.2) Sensors 学习——G-sensor,
  6. Android练习项目 Mp3播放器实现(一)
  7. Android Studio 基础 之 一键快速实现一
  8. Android中自定义ListView无法响应OnItemC
  9. Android心得3--拨号器
  10. Android中基于心知天气API获取天气信息