当前位置:   article > 正文

Android CardView源码分析_cardview 代码解读

cardview 代码解读

首先放一张CardView的结构图

在这里插入图片描述

对cardview做一个解析:

  • 首先介绍一下CardView经常使用的属性
    cardview_cardBackgroundColor 设置背景色
    cardview_cardCornerRadius 设置圆角大小
    cardview_cardElevation 设置z轴阴影
    cardview_cardMaxElevation 设置z轴最大高度值
    cardview_cardUseCompatPadding 是否使用CompatPadding
    cardview_cardPreventCornerOverlap 是否使用PreventCornerOverlap ,防止内容和边角的重叠
    cardview_contentPadding 内容的padding
    xml里面加上这么一句话 xmlns:card_view="http://schemas.android.com/apk/res-auto"
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 从UML图我们可以看见CardView继承FramelayoutCardView内部持有了一个CardViewImpl实例和一个CardViewDelegate实例,CardViewImpl主要是CardView内部对于圆角阴影等 cardview重要特性在不同版本上的兼容,CardViewImpl是对CardView具有的行为的抽象,在不同版本下有不同的实现,比如CardViewApi21CardViewJellybeanMr1CardViewGingerbread

CardView阴影的实现

  • CardView对于Lollipop以上版本,是直接通过elevation来实现的阴影。
    • android5.0 引入了Z轴的概念,于是就有这种风格,也就是目前比较火的Material Design。
    • android:elevation 设置该组件“浮”起来的高度,to难过过设置该属性可以让该组件呈现3D效果。
    • android:translationZ 设置该组件在Z方向(垂直屏幕方向)上的位移。
    • eleavation是静态的成员,translationZ是用来做动画。
  • 但是elevation需要有margin配合才能透出阴影,比如elevation:10dp, margin:10dp, 这样才能配合实现阴影。
  • 对于Lollipop版本以下的,是通过在padding里面透出阴影来实现的,查看源码发现是通过RoundRectDrawableWithShadow 这个drawble充当背景来实现的,而RoundRectDrawableWithShadow这个里面是通过RadialGradientLinearGradient两种shader(纹理)来实现的渐变模拟的阴影效果。
  • 可以尝试以下,给CardView直接设置setPadding时是没有用的,为什么呢,里面重写了setPadding方法,是空实现。
    @Override
    public void setPadding(int left, int top, int right, int bottom) {
        // NO OP
    }
    
    • 1
    • 2
    • 3
    • 4
  • 对应的是setContentPadding,我们可以看一下setContentPadding的实现,可以看到CardViewDelegate里面有这么一句话
    @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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 由此明白了,对于5.0以下系统,shadow的阴影由padding漏出,是必须留出来的,而剩下设置的contentPadding才是你设置的padding
  • 在使用CardView,我踩了个坑,在把cardviewBackgroundDrawable给替换了之后,结果之后再怎么设置颜色和圆角等属性都不起作用了,这是为什么呢?
    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;
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
  • 可以看到,所以对于圆角背景颜色等操作 都是代理给mCardViewDelegate来完成的,而通过mCardViewDelegate获取的背景Drawable是它保存的mCardBackground实例,一旦直接给CardView设置了一个BackgroundDrawble,这个drawblemCardViewDelegate保存的mCardBackground就不再是一个,那么之后对于背景的操作就是对牛弹琴,改变的只是mCardBackground的属性,而真正的cardview的属性没有改变。
  • cardview_cardPreventCornerOverlap 是否使用PreventCornerOverlap ,防止内容和边角的重叠,之前一直没搞懂这个属性的意思,直到我看到了RoundRectDrawableWithShadow中这段源码,还记得之前说的吗,RoundRectDrawableWithShadow实现了5.0以下的阴影
    static float calculateVerticalPadding(float maxShadowSize, float cornerRadius,
            boolean addPaddingForCorners) {
        if (addPaddingForCorners) {
            return (float) (maxShadowSize * SHADOW_MULTIPLIER + (1 - COS_45) * cornerRadius);
        } else {
            return maxShadowSize * SHADOW_MULTIPLIER;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 这里addPaddingForCorners对应的就是PreventCornerOverlap这个boolean变量,通过+ (1 - COS_45) * cornerRadius,保证了内容不会超过圆角的边界。
  • CardView水波纹效果。既然CardView继承自Framelayout,那么和Framelayout实现水波纹是一个效果。直接给 CardView 加上android:foreground="?attr/selectableItemBackground" 这个属性会在 Lollipop 上自动加上 Ripple 效果,在旧版本则是一个变深/变亮的效果。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Monodyee/article/detail/536694
推荐阅读
相关标签
  

闽ICP备14008679号