3.1.4_cardView原理解析

CardView继承自FrameLayout,对于不同的版本,有不同的实现类。

static {
    if (VERSION.SDK_INT >= 21) {
        IMPL = new CardViewApi21Impl();
    } else if (VERSION.SDK_INT >= 17) {
        IMPL = new CardViewApi17Impl();
    } else {
        IMPL = new CardViewBaseImpl();
    }

    IMPL.initStatic();
}

在onMeasure里面,对系统版本做了区分。
如果API>=21则不处理,否则会预留出阴影的空间。

接下来看一下API21的实现CardViewApi21Impl

public void initialize(CardViewDelegate cardView, Context context, ColorStateList backgroundColor, float radius, float elevation, float maxElevation) {
    RoundRectDrawable background = new RoundRectDrawable(backgroundColor, radius);
    cardView.setCardBackground(background);
    View view = cardView.getCardView();
    view.setClipToOutline(true);
    view.setElevation(elevation);
    this.setMaxElevation(cardView, maxElevation);
}  

可以看到,获取了一个View,并对这个View进行了裁剪,设置了阴影大小和最大阴影大小。

public void setMaxElevation(CardViewDelegate cardView, float maxElevation) {
    this.getCardBackground(cardView).setPadding(maxElevation, cardView.getUseCompatPadding(), cardView.getPreventCornerOverlap());
    this.updatePadding(cardView);
}   

来看setMaxElevation中的updatePadding,可以看到

public void updatePadding(CardViewDelegate cardView) {
    if (!cardView.getUseCompatPadding()) {
        cardView.setShadowPadding(0, 0, 0, 0);
    } else {
        float elevation = this.getMaxElevation(cardView);
        float radius = this.getRadius(cardView);
        int hPadding = (int)Math.ceil((double)RoundRectDrawableWithShadow.calculateHorizontalPadding(elevation, radius, cardView.getPreventCornerOverlap()));
        int vPadding = (int)Math.ceil((double)RoundRectDrawableWithShadow.calculateVerticalPadding(elevation, radius, cardView.getPreventCornerOverlap()));
        cardView.setShadowPadding(hPadding, vPadding, hPadding, vPadding);
    }
}

这里的CardViewDelegate是在CardView的构造方法中初始化的,这里计算出相应的padding之后,会调用CardViewDelegate.setShadowPadding

public CardView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    this.mContentPadding = new Rect();
    this.mShadowBounds = new Rect();
    this.mCardViewDelegate = new CardViewDelegate() {
        private Drawable mCardBackground;

        public void setCardBackground(Drawable drawable) {
            this.mCardBackground = drawable;
            CardView.this.setBackgroundDrawable(drawable);
        }

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

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

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

        public void setMinWidthHeightInternal(int width, int height) {
            if (width > CardView.this.mUserSetMinWidth) {
                CardView.super.setMinimumWidth(width);
            }

            if (height > CardView.this.mUserSetMinHeight) {
                CardView.super.setMinimumHeight(height);
            }

        }

        public Drawable getCardBackground() {
            return this.mCardBackground;
        }

        public View getCardView() {
            return CardView.this;
        }
    };
    TypedArray a = context.obtainStyledAttributes(attrs, styleable.CardView, defStyleAttr, style.CardView);
    ColorStateList backgroundColor;
    if (a.hasValue(styleable.CardView_cardBackgroundColor)) {
        backgroundColor = a.getColorStateList(styleable.CardView_cardBackgroundColor);
    } else {
        TypedArray aa = this.getContext().obtainStyledAttributes(COLOR_BACKGROUND_ATTR);
        int themeColorBackground = aa.getColor(0, 0);
        aa.recycle();
        float[] hsv = new float[3];
        Color.colorToHSV(themeColorBackground, hsv);
        backgroundColor = ColorStateList.valueOf(hsv[2] > 0.5F ? this.getResources().getColor(color.cardview_light_background) : this.getResources().getColor(color.cardview_dark_background));
    }

    float radius = a.getDimension(styleable.CardView_cardCornerRadius, 0.0F);
    float elevation = a.getDimension(styleable.CardView_cardElevation, 0.0F);
    float maxElevation = a.getDimension(styleable.CardView_cardMaxElevation, 0.0F);
    this.mCompatPadding = a.getBoolean(styleable.CardView_cardUseCompatPadding, false);
    this.mPreventCornerOverlap = a.getBoolean(styleable.CardView_cardPreventCornerOverlap, true);
    int defaultPadding = a.getDimensionPixelSize(styleable.CardView_contentPadding, 0);
    this.mContentPadding.left = a.getDimensionPixelSize(styleable.CardView_contentPaddingLeft, defaultPadding);
    this.mContentPadding.top = a.getDimensionPixelSize(styleable.CardView_contentPaddingTop, defaultPadding);
    this.mContentPadding.right = a.getDimensionPixelSize(styleable.CardView_contentPaddingRight, defaultPadding);
    this.mContentPadding.bottom = a.getDimensionPixelSize(styleable.CardView_contentPaddingBottom, defaultPadding);
    if (elevation > maxElevation) {
        maxElevation = elevation;
    }

    this.mUserSetMinWidth = a.getDimensionPixelSize(styleable.CardView_android_minWidth, 0);
    this.mUserSetMinHeight = a.getDimensionPixelSize(styleable.CardView_android_minHeight, 0);
    a.recycle();
    IMPL.initialize(this.mCardViewDelegate, context, backgroundColor, radius, elevation, maxElevation);
}

可以看到setShadowPadding中,直接调用了CardView的setPadding(CardView没有重写这个方法,所以实际是调用View.setPadding)

小结

CardView的源码主要就是针对阴影和类边距效果在不同的系统版本上面做了不同的处理。

在使用CardView的时候,为了保持cardview在不同的版本中的一致性,一般情况下,都要加

    app:cardPreventCornerOverlap="false"
    app:cardUseCompatPadding="true"  

app:cardUseCompatPadding boolean 在Android 5.0及以上平台中,设置是否要添加padding,5.0以下默认添加padding。默认值为false
app:cardPreventCornerOverlap boolean 是否给content添加padding,来阻止与圆角重叠,默认值为true

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

氦客

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值