• CardView 简介和使用


    CardView 简介
    本文链接:https://blog.csdn.net/ShawnXiaFei/article/details/81568537
    CardView 是 Google 官方发布 MD 风格卡片布局控件,开发者可以很方便的使用它将布局做成卡片效果。在使用 CardView 之前,多少应该对它有一定的了解,下面将对其实现做简单的介绍。
    自定义属性
    CardView 继承自 FrameLayout,并在其基础上添加了圆角和阴影等效果。为了更方便的使用这些效果,Google 提供了一系列的自定义属性,这些属性在类注释中都有列出来,如下:
     /**
     * @attr ref android.support.v7.cardview.R.styleable#CardView_cardBackgroundColor
     * @attr ref android.support.v7.cardview.R.styleable#CardView_cardCornerRadius
     * @attr ref android.support.v7.cardview.R.styleable#CardView_cardElevation
     * @attr ref android.support.v7.cardview.R.styleable#CardView_cardMaxElevation
     * @attr ref android.support.v7.cardview.R.styleable#CardView_cardUseCompatPadding
     * @attr ref android.support.v7.cardview.R.styleable#CardView_cardPreventCornerOverlap
     * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPadding
     * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPaddingLeft
     * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPaddingTop
     * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPaddingRight
     * @attr ref android.support.v7.cardview.R.styleable#CardView_contentPaddingBottom
     */
    public class CardView extends FrameLayout {

    这些属性的作用和用法如下:
    CardView_cardBackgroundColor        设置背景色
    CardView_cardCornerRadius           设置圆角大小
    CardView_cardElevation              设置z轴阴影
    CardView_cardMaxElevation           设置z轴最大高度值
    CardView_cardUseCompatPadding       是否使用CompadPadding
    设置内边距,V21+的版本和之前的版本具有一样的计算方式。
    部分机器不开这个属性会导致卡片效果“消失”,如荣耀6(6.0系统)。
    CardView_cardPreventCornerOverlap   是否使用PreventCornerOverlap
    在V20和之前的版本中添加内边距,这个属性为了防止内容和边角的重叠
    CardView_contentPadding             内部边距,子View与CardView的距离
    CardView_contentPaddingLeft         内部左侧边距
    CardView_contentPaddingTop          内部顶部边距
    CardView_contentPaddingRight        内部右侧边距
    CardView_contentPaddingBottom       内部底部边距

    CardViewImpl 接口
    跟着源码往下看,接下来就是做多 API 版本适配的代码,这段代码使得不同版本的 Android 能达到相同或者相似的效果,尽可能的做到了兼容。这里 CardViewImpl 的几个子类实现请自行查阅,这里不多说了。
    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();
    }
    上面这段代码很有意思,首先它是static{}包裹的静态代码块,而静态代码块是属于类的,只会在类被加载到内存时执行一次,以后不管如何实例化,new 出多少实例对象,静态代码块都不会再执行了。其次,IMPL 对象是是static final修饰的,这就意味着 IMPL 对象也是属于类,并且只能被初始化一次。
    final 修饰的对象,若是基本类型+String,则其值不能修改;若是复杂类型,则其引用不能修改。
    基本类型+String的值、复杂类型的引用,存储在栈中;复杂类型的实体类容存储在堆中。final 是指明栈中的类容不能修改。
    那么,一旦 CardView 被加载到内存,IMPL 对象(地址)就不会再变化了,也就会被后续系统中所有实例化的 CardView 对象共享。而纵观整个 CardView 的源码,我们会发现 IMPL 对象几乎出现在 CardView 的所有方法中,那么是不是系统中所有的 CardView 实例化对象都会有相同的表现呢?
    实际使用中我们发现,即便一个APP内部的多个CardView也能有不同的表现,更不用说整个系统上的所有APP了,那这又是怎么做到的呢?
    我们接着看下 CardViewImpl 接口的定义:
    /**
     * Interface for platform specific CardView implementations.
     */
    interface CardViewImpl {
        void initialize(CardViewDelegate cardView, Context context, ColorStateList backgroundColor,
                float radius, float elevation, float maxElevation);
        void setRadius(CardViewDelegate cardView, float radius);
        float getRadius(CardViewDelegate cardView);
        void setElevation(CardViewDelegate cardView, float elevation);
        float getElevation(CardViewDelegate cardView);
        void initStatic();
        void setMaxElevation(CardViewDelegate cardView, float maxElevation);
        float getMaxElevation(CardViewDelegate cardView);
        float getMinWidth(CardViewDelegate cardView);
        float getMinHeight(CardViewDelegate cardView);
        void updatePadding(CardViewDelegate cardView);
        void onCompatPaddingChanged(CardViewDelegate cardView);
        void onPreventCornerOverlapChanged(CardViewDelegate cardView);
        void setBackgroundColor(CardViewDelegate cardView, @Nullable ColorStateList color);
        ColorStateList getBackgroundColor(CardViewDelegate cardView);
    }
    不难发现,这里面几乎所有方法都有一个参数——CardViewDelegate,在CardView的方法调用时,会通过早已初始化的 IMPL 调用对应的方法,并传入一个mCardViewDelegate对象,并通过它进行下一步操作。如:
    /**
     * Updates the background color of the CardView
     *
     * @param color The new color to set for the card background
     * @attr ref android.support.v7.cardview.R.styleable#CardView_cardBackgroundColor
     */
    public void setCardBackgroundColor(@ColorInt int color) {
        IMPL.setBackgroundColor(mCardViewDelegate, ColorStateList.valueOf(color));
    }
    CardViewDelegate 代理
    接下来就简单说下 CardViewDelegate 对象是如何工作的。
    首先是定义,这一系列方法定义与 CardView 提供的方法迷之相似。
    /**
     * Interface provided by CardView to implementations.
     * <p>
     * Necessary to resolve circular dependency between base CardView and platform implementations.
     */
    interface CardViewDelegate {
        void setCardBackground(Drawable drawable);
        Drawable getCardBackground();
        boolean getUseCompatPadding();
        boolean getPreventCornerOverlap();
        void setShadowPadding(int left, int top, int right, int bottom);
        void setMinWidthHeightInternal(int width, int height);
        View getCardView();
    }
    然后 CardViewDelegate 的实例化是在 CardView 中进行的,在 CardView 代码末尾可看到其实现:
    private final CardViewDelegate mCardViewDelegate = new CardViewDelegate() {
        ······
    }
    这里没有使用 static,那么这个 mCardViewDelegate 对象在 CardView 实例化时也会 new 一个新的,然后通过不同 mCardViewDelegate 对象,就做到了一个系统上不同CardView有不同表现。
    最后这一系列操作的示意图大致是这样的:
    这一系列的操作,将 CardView 的实现分成多个类,各个类只处理和自己相关的逻辑,简化了 CardView 自身逻辑。同时,能很方便的做到多平台适配,不需要将各个平台特定的实现代码全部挤在 CardView 内部。而且能很方便进行扩展,如添加新平台、新特性,而且不会对 CardView 的代码造成很大改动,只需要添加新的 IMPL,并在static{}中添加新分支即可。
    CardView 使用
    添加依赖库
    CardView 是随 MD 推出的补充库,并非 SDK 的内容,因此在使用 CardView 时,必须先引入依赖库:
    implementation 'com.android.support:cardview-v7:xx.x.x'
    1
    使用 CardView 布局
    前面已经介绍了,CardView 继承自 FrameLayout,那么我们就可以直接在布局中,将CardView作为容器,放入其它控件即可。
    如果已有现成的布局,想再引入卡片效果,也只需要在已有布局最外层添加 CardView 即可。
    举个栗子:
    <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:layout_margin="@dimen/dp8"
        android:orientation="vertical"
        app:cardBackgroundColor="@color/white"
        app:cardCornerRadius="@dimen/dp8"
        app:cardElevation="@dimen/dp8"
        app:cardUseCompatPadding="true"
        app:contentPadding="@dimen/dp8">
        <TextView
            android:id="@+id/tvTitle"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="测试 卡片 效果"
            android:textSize="@dimen/sp32" />
    </android.support.v7.widget.CardView>

    前面介绍属性已经说了,部分机器(如荣耀6,6.0系统)如果不打开 cardUseCompatPadding,将不会呈现出卡片效果。因此建议打开。
    效果如下:

    类似效果

    要实现卡片效果,除了用 CardView 以外,还有其它方法,比如使用shape+elevation。
    举个栗子:
    先定义一个shape,用作背景。
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">//shape样式
        //圆角
        <corners android:radius="@dimen/dp8" />
        //边框
        <stroke
            android:width="1dp"
            android:color="@color/divider" />
        //内边距
        <padding
            android:bottom="@dimen/dp8"
            android:left="@dimen/dp8"
            android:right="@dimen/dp8"
            android:top="@dimen/dp8" />
        //内部填充
        <solid android:color="@color/white" />
    </shape>

    然后在布局中引用:
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="top|center_horizontal"
        android:layout_margin="@dimen/dp8"
        android:background="@drawable/shape"
        android:elevation="@dimen/dp8"    //z轴高度,控制阴影效果
        android:text="测试 卡片 效果"
        android:textSize="@dimen/sp32" />
    运行效果:
    可以看到,与前面使用 CardView 的效果几乎一样。
    但是,elevation属性也是随MD出来的,它只支持 5.0+(也就是API21+)的系统。因此,如果要卡片效果能想兼容低版本系统,那还是应该优先考虑用 CardView。
    ————————————————
  • 相关阅读:
    net.sf.json Maven依赖配置
    springboot 测试 出错
    PowerDesigner 中SQL文件、数据库表反向生成PDM
    魔板问题(搜索)
    九宫重排(搜索)
    选点(树的遍历)
    【搜索】桐桐的运输方案
    细胞(搜索)
    传球游戏(dp)
    脚本_检测mysql存活状态
  • 原文地址:https://www.cnblogs.com/it-tsz/p/11572394.html
Copyright © 2020-2023  润新知