【MaterialDesign】CardView

  CardView是用于实现卡片式布局效果的重要控件,由appcompat-v7库提供。实际上CardView也是一个FrameLayout,只是额外提供圆角和阴影等效果。
  玩Android这么久了,几个应用都使用了CardView。今天在改一个项目时,留意到两个使用CardView的地方,具有类似的代码,但是实现的的效果不太一样,因此还是决定写篇文章来理清CardView开发过程中的坑。

1、使用方法

 在app的build.gradle文件中添加依赖。

implementation 'com.android.support:appcompat-v7:26.1.0'
implementation 'com.android.support:cardview-v7:26.1.0'

 在xml布局文件中使用CardView。




    


2、CardView常用属性

app:cardBackGroundColor 设置背景颜色
app:cardCornerRadius 设置圆角大小
app:cardElevation 设置z轴阴影效果
app:cardMaxElevation 设置z轴的最大高度值
app:contentPadding 内容距离边界的距离
app:contentPaddingXXX 设置局部的内边距,代替Padding,在CardView中设置padding不起作用
app:cardUseCompatPadding 是否使用CompatPadding,如果需要将CardView与其他视图对齐,在21以下,可以将此标记为true,在21以上平台,添加相同的填充值。
app:cardPreventCornerOverlap 是否裁剪边界以防止重叠

 CardView常用属性就是这些,看似不多,实质很多坑。

3、CardView开发中的问题

 CardView是在Android 5.0(Lollipop)也就是API 21时推出的控件,因此在Android 5.0前使用CardView要考虑适配的问题。

1. 阴影Padding

 在Android 5.0之前的系统,CardView会自动添加一些额外的Padding控件来绘制阴影部分,导致了Android 5.0前后的不同系统上CardView的大小会不一样。为了解决这个问题,可以有如下方法:

①使用不同API版本的dimension资源匹配,也就是借助vales和values-21文件夹中不同的dimens.xml文件
②使用setUseCompadding熟悉,设置为ture,可以让CardView在不同系统中使用相同的padding值。
2. 圆角覆盖

 在API21前CradView不会裁剪内容来满足圆角的需求,而是使用了padding的代替方案,设置了内边距,免得裁剪内容。API21以后,CardView会自动裁剪内容元素以适应圆角。
 在CardView中,有个app:cardPreventCornerOverlap 的属于,设置该属性为true后,CardView将不会添加Padding。

3. lift-on-touch

 在Material Design中有一个叫触碰抬起的交互效果,也就是在z轴上发生位移,产生一个阴影加深的效果。lift-on-touch触碰抬起效果是通过改变translationZ值,沿着Z轴发生变化,就会导致阴影效果的变化:
【MaterialDesign】CardView_第1张图片
 因为在API21中有个新的属性android:stateListAnimator,可以在API21以上系统实现lift-on-touch效果。
 在CardView属性中添加:

android:stateListAnimator="@drawable/lift_on_touch"

 在drawable中添加lift-on-touch.xml文件



    
        
            
        
    
    
        
            
        
    

4. CardView的setBackgroundDrawable。

 使用场景如下:
  在Item中有个CheckBox选择,根据CheckBox的状态设置背景颜色,通过setbackDrawable设置。

if (task.getFinished()) {
    holder.view.setBackgroundDrawable(holder.view.getResources().getDrawable(R.drawable.list_completed_touch_feedback));
} else {
    holder.view.setBackgroundDrawable(holder.view.getResources().getDrawable(R.drawable.touch_feedback));
}

 设置了背景后,导致了图一的效果:CardView的圆角、阴影等效果完全实现不了。经过测试,如图二所示:在CardView中设置了layout_margin后,部分CardView效果能显示。如图三所示,不设置backgroundDrawable和layout_margin后,可以显示CardView的圆角和阴影,但是无法根据CheckBox的状态高亮显示任务是否完成。
【MaterialDesign】CardView_第2张图片
 查看CardView的代码:

private final CardViewDelegate mCardViewDelegate = new CardViewDelegate() {
    private Drawable mCardBackground;

    @Override
    public void setCardBackground(Drawable drawable) {
        mCardBackground = drawable;
        setBackgroundDrawable(drawable);
    }

    @Override
    public boolean getUseCompatPadding() {
        return CardView.this.getUseCompatPadding();
    }

    @Override
    public boolean getPreventCornerOverlap() {
        return CardView.this.getPreventCornerOverlap();
    }

    @Override
    public void setShadowPadding(int left, int top, int right, int bottom) {
        mShadowBounds.set(left, top, right, bottom);
        CardView.super.setPadding(left + mContentPadding.left, top + mContentPadding.top,
                right + mContentPadding.right, bottom + mContentPadding.bottom);
    }

    @Override
    public void setMinWidthHeightInternal(int width, int height) {
        if (width > mUserSetMinWidth) {
            CardView.super.setMinimumWidth(width);
        }
        if (height > mUserSetMinHeight) {
            CardView.super.setMinimumHeight(height);
        }
    }

    @Override
    public Drawable getCardBackground() {
        return mCardBackground;
    }

    @Override
    public View getCardView() {
        return CardView.this;
    }
};

 可以看到,所有对于圆角背景颜色等操作,都是代理给mCardViewDelegate来完成的,而通过mCardViewDelegate获取背景Drawable是它保存的mCardBackground实例,一旦直接给CardView设置BackgroundDrawable后,这个drawable和mCardViewDelegate保存的mCardBackground就不再是同一个了,那么后续对背景的操作都没有效果,改变的只是mCardBackground的属性,而真正的cardView的属性没有改变。
 为了实现上述效果,将CheckBox改变的背景颜色改为CardView内部中RelativeLayout的背景,从而不影响CardView的效果,也就是说CardView实现了圆角、阴影、lift-on-touch等效果后,再根据CheckBox的状态来改变RelativeLayout的背景颜色。



    

        

            

            ...

    

 MaterialDesign中提供的许多控件,给开发带来了许多便利,同时也有许多适配的问题需要开发者进行处理。

你可能感兴趣的:(android)