【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。

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cardCornerRadius="5dp"
    app:cardElevation="2dp"
    app:cardPreventCornerOverlap="true"
    app:cardUseCompatPadding="true"
    app:contentPadding="5dp"
    app:contentPaddingBottom="8dp"
    app:contentPaddingLeft="16dp"
    app:contentPaddingRight="16dp">

    <TextView
        android:id="@+id/tv_list_item_list_name"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_marginLeft="5dp"
        android:layout_toRightOf="@id/v_list_item_priority"
        android:gravity="center_vertical"
        android:text="清单名"
        android:textSize="20sp" />
</android.support.v7.widget.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轴发生变化,就会导致阴影效果的变化:
在这里插入图片描述
 因为在API21中有个新的属性android:stateListAnimator,可以在API21以上系统实现lift-on-touch效果。
 在CardView属性中添加:

android:stateListAnimator="@drawable/lift_on_touch"

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

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:state_enabled="true"
        android:state_pressed="true">
        <set>
            <objectAnimator
                android:duration="@android:integer/config_shortAnimTime"
                android:propertyName="translationZ"
                android:valueTo="6dp"
                android:valueType="floatType"/>
        </set>
    </item>
    <item>
        <set>
            <objectAnimator
                android:duration="@android:integer/config_shortAnimTime"
                android:propertyName="translationZ"
                android:valueTo="0"
                android:valueType="floatType"/>
        </set>
    </item>
</selector>
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的状态高亮显示任务是否完成。
在这里插入图片描述
 查看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的背景颜色。

<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:stateListAnimator="@drawable/lift_on_touch"
    app:cardCornerRadius="5dp"
    app:cardElevation="2dp"
    app:cardUseCompatPadding="true">

    <RelativeLayout
        android:id="@+id/rl_task_item"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingLeft="16dp"
        android:paddingRight="16dp"
        android:paddingTop="8dp"
        android:paddingBottom="8dp">

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal">

            <CheckBox
                android:id="@+id/cb_task_item"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical" />

            ...

    </RelativeLayout>
</android.support.v7.widget.CardView>
 MaterialDesign中提供的许多控件,给开发带来了许多便利,同时也有许多适配的问题需要开发者进行处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值