(三十六)CardView 使用及源码分析

来源:互联网 发布:多线程cpu优化 编辑:程序博客网 时间:2024/06/02 06:38

版权声明:本文为博主原创文章,未经博主允许不得转载。

本文纯个人学习笔记,由于水平有限,难免有所出错,有发现的可以交流一下。

一、使用

1.demo

CardView 的使用很简单,直接上个 demo 看一下。

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.xiaoyue.cardview.MainActivity">    <android.support.v7.widget.CardView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        app:cardCornerRadius="15dp">        <ImageView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:src="@drawable/a"/>    </android.support.v7.widget.CardView></android.support.constraint.ConstraintLayout>

直接在布局文件中使用即可。

效果1:
这里写图片描述

这是在安卓 5.0 以上的系统,在安卓 5.0 以下的系统显示的效果不一样。

效果2:
这里写图片描述

在布局文件中,给 CardView 设置 app:cardCornerRadius (圆角)属性,但是实际生效的是 CardView 下的子控件 ImageView。

2.使用文字

对比上面两个效果图,可以发现,在 5.0 以下系统,CardView 下边沿有一个默认的 Padding,在 5.0 以上是没有的。

这时候如果使用文字的话会导致文字部分被遮挡住。

5.0 以上效果:

这里写图片描述

5.0 以下效果:

这里写图片描述

这时候就需要对 CardView 使用 contentPadding 进行边距的设置。

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:app="http://schemas.android.com/apk/res-auto"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.xiaoyue.cardview.MainActivity">    <android.support.v7.widget.CardView        android:layout_width="400dp"        android:layout_height="200dp"        app:cardCornerRadius="25dp"        app:contentPadding="10dp">        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="@string/app_name"            android:textSize="20dp"/>    </android.support.v7.widget.CardView></android.support.constraint.ConstraintLayout>

效果:

这里写图片描述

3.其他属性

 ● android:cardCornerRadius  ○ 在xml文件中设置card圆角的大小 ● CardView.setRadius  ○ 在代码中设置card圆角的大小 ● android:cardBackgroundColor  ○ 在xml文件中设置card背景颜色 ● android:elevation  ○ 在xml文件中设置阴影的大小 ● card_view:cardElevation  ○ 在xml文件中设置阴影的大小 ● card_view:cardMaxElevation  ○ 在xml文件中设置阴影最大高度 ● card_view:cardCornerRadius  ○ 在xml文件中设置卡片的圆角大小 ● card_view:contentPadding  ○ 在xml文件中设置卡片内容于边距的间隔 ● card_view:contentPaddingBottom  ○ 在xml文件中设置卡片内容于下边距的间隔 ● card_view:contentPaddingTop  ○ 在xml文件中设置卡片内容于上边距的间隔 ● card_view:contentPaddingLeft  ○ 在xml文件中设置卡片内容于左边距的间隔 ● card_view:contentPaddingRight  ○ 在xml文件中设置卡片内容于右边距的间隔 ● card_view:contentPaddingStart  ○ 在xml文件中设置卡片内容于边距的间隔起始 ● card_view:contentPaddingEnd  ○ 在xml文件中设置卡片内容于边距的间隔终止 ● card_view:cardUseCompatPadding  ○ 在xml文件中设置内边距,V21+的版本和之前的版本仍旧具有一样的计算方式 ● card_view:cardPreventConrerOverlap  ○ 在xml文件中设置内边距,在V20和之前的版本中添加内边距,这个属性为了防止内容和边角的重叠

二、源码

public class CardView extends FrameLayout {    private static final int[] COLOR_BACKGROUND_ATTR = {android.R.attr.colorBackground};    private static final CardViewImpl IMPL;    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();    }    ...    private final CardViewDelegate mCardViewDelegate = new CardViewDelegate() {        ...    }}

首先,CardView 继承于 FrameLayout ,拥有 FrameLayout 的特性。CardView 跟 AppCompat 使用了一样的机制,根据版本进行判断,去实例化不同的实现类,以及使用代理进行对象的操作。

这边从设置圆角开始分析,为什么属性添加在 CardView 却作用于 CardView 下的子控件。

CardView 的构造函数调用了初始化方法 initialize()。

initialize:

    private void initialize(Context context, AttributeSet attrs, int defStyleAttr) {        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CardView, defStyleAttr,                R.style.CardView);        ...        IMPL.initialize(mCardViewDelegate, context, backgroundColor, radius,                elevation, maxElevation);    }

initialize 进行了 xml 设置的属性获取,最终调用 CardViewImpl 的 initialize 方法,上面说了,CardViewImpl 会根据版本去实例化不同的实现类。

CardViewApi21Impl

class CardViewApi21Impl implements CardViewImpl {    @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);        view.setElevation(elevation);        setMaxElevation(cardView, maxElevation);    }    ...}

在安卓 5.0 以上的时候,实例化了 CardViewApi21Impl 对象,CardViewApi21Impl 的 initialize 方法有一个 RoundRectDrawable ,并把这个设置为 CardView 的 Background。我们看一下 RoundRectDrawable 。

RoundRectDrawable :

class RoundRectDrawable extends Drawable {    ...    @Override    public void draw(Canvas canvas) {        final Paint paint = mPaint;        final boolean clearColorFilter;        if (mTintFilter != null && paint.getColorFilter() == null) {            paint.setColorFilter(mTintFilter);            clearColorFilter = true;        } else {            clearColorFilter = false;        }        canvas.drawRoundRect(mBoundsF, mRadius, mRadius, paint);        if (clearColorFilter) {            paint.setColorFilter(null);        }    }        ...        /**     * Ensures the tint filter is consistent with the current tint color and     * mode.     */    private PorterDuffColorFilter createTintFilter(ColorStateList tint, PorterDuff.Mode tintMode) {        if (tint == null || tintMode == null) {            return null;        }        final int color = tint.getColorForState(getState(), Color.TRANSPARENT);        return new PorterDuffColorFilter(color, tintMode);    }}

RoundRectDrawable 的 draw 方法设置了一个 setColorFilter,这个 ColorFilter 是通过 createTintFilter 获取到的,然后调用 canvas.drawRoundRect 就会跟原先的背景进行混合,tintMode 就是混合模式 PorterDuff.Mode.SRC_IN。所以会产生图片是圆角的效果。
(混合模式具体链接:http://blog.csdn.net/qq_18983205/article/details/72810681)

再查看 CardViewApi17Impl ,这个实现类没有 RoundRectDrawable 这个东西,所以不能使图片变成圆角。

原创粉丝点击