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

3.1.4_cardView原理解析相关推荐

  1. Spark Shuffle原理解析

    Spark Shuffle原理解析 一:到底什么是Shuffle? Shuffle中文翻译为"洗牌",需要Shuffle的关键性原因是某种具有共同特征的数据需要最终汇聚到一个计算节 ...

  2. 秋色园QBlog技术原理解析:性能优化篇:用户和文章计数器方案(十七)

    2019独角兽企业重金招聘Python工程师标准>>> 上节概要: 上节 秋色园QBlog技术原理解析:性能优化篇:access的并发极限及分库分散并发方案(十六)  中, 介绍了 ...

  3. Tomcat 架构原理解析到架构设计借鉴

    ‍ 点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 Tomcat 架构原理解析到架构设计借鉴 Tomcat 发展这 ...

  4. 秋色园QBlog技术原理解析:性能优化篇:数据库文章表分表及分库减压方案(十五)...

    文章回顾: 1: 秋色园QBlog技术原理解析:开篇:整体认识(一) --介绍整体文件夹和文件的作用 2: 秋色园QBlog技术原理解析:认识整站处理流程(二) --介绍秋色园业务处理流程 3: 秋色 ...

  5. CSS实现元素居中原理解析

    原文:CSS实现元素居中原理解析 在 CSS 中要设置元素水平垂直居中是一个非常常见的需求了.但就是这样一个从理论上来看似乎实现起来极其简单的,在实践中,它往往难住了很多人. 让元素水平居中相对比较简 ...

  6. 秋色园QBlog技术原理解析:Web之页面处理-内容填充(八)

    文章回顾: 1: 秋色园QBlog技术原理解析:开篇:整体认识(一) --介绍整体文件夹和文件的作用 2: 秋色园QBlog技术原理解析:认识整站处理流程(二) --介绍秋色园业务处理流程 3: 秋色 ...

  7. 秋色园QBlog技术原理解析:UrlRewrite之无后缀URL原理(三)

    文章回顾: 1: 秋色园QBlog技术原理解析:开篇:整体认识(一) --介绍整体文件夹和文件的作用 2: 秋色园QBlog技术原理解析:认识整站处理流程(二) --介绍秋色园业务处理流程 本节,将从 ...

  8. Android之Butterknife原理解析

    转载请标明出处:[顾林海的博客] 个人开发的微信小程序,目前功能是书籍推荐,后续会完善一些新功能,希望大家多多支持! ##前言 Butterknife是一个专注于Android系统的View注入框架, ...

  9. 【深度学习】谷歌大脑EfficientNet的工作原理解析

    [深度学习]谷歌大脑EfficientNet的工作原理解析 文章目录 1 知识点准备1.1 卷积后通道数目是怎么变多的1.2 EfficientNet 2 结构2.1 方式2.2 MBConv卷积块2 ...

  10. Web APi之过滤器执行过程原理解析【二】(十一)

    前言 上一节我们详细讲解了过滤器的创建过程以及粗略的介绍了五种过滤器,用此五种过滤器对实现对执行Action方法各个时期的拦截非常重要.这一节我们简单将讲述在Action方法上.控制器上.全局上以及授 ...

最新文章

  1. 蓝桥杯 1427 买不到的数目 (模拟)
  2. 【Leetcode】【Medium】Rotate Image
  3. slf4j+log4j2的整合配置
  4. oracle 约束 Oracle 10g学习系列(5)
  5. 《数据结构与算法分析》习题-----第二章(3)(关于list的题目)
  6. 2012.4.16总结(三)
  7. mysql中设置字符,MySQL 修改默认字符集
  8. 【翻译】CodeMix使用教程(四):调试
  9. Excel VBA函数和过程调用方法总结(跨文件调用函数和过程)
  10. c语言之sizeof与strlen全
  11. 云呐|加强固定资产设备信息化管理工作
  12. wifi动不动就断开_WIFI经常自动断网,大多数是因为此原因
  13. 如何通过限制 IP 相关信息 | 控制用户访问站点频率
  14. html5调用安卓锁屏,HTML5实现APP永不锁屏
  15. Sting的简介以及用法
  16. Python爬虫视频课程:中国女性胸部大小分析-李宁-专题视频课程
  17. 用层次分析法分析如何选购电脑
  18. 12.13 Daily Scrum
  19. 京东2016实习生招聘笔试真题-技术岗位选择题A
  20. 带你走进k8s的世界----------什么是k8s?

热门文章

  1. st7789 旋转_玩转 ESP32 + Arduino(二十八) TFT_eSPI库驱动ST7789
  2. android 让程序在后台运行,android – 如何让我的应用程序在后台运行?
  3. 视频教程-思科CCNP专题系列②:EIGRP路由协议-思科认证
  4. 科宇扫地机器人_扫地谁更精准更干净?新一代3D视讯+激光成像 PK 老式激光扫描...
  5. 命令总结(一)-TcpDump命令使用详情
  6. 浏览器window对象
  7. ubuntu 安装万能五笔
  8. Inno Setup打包教程
  9. 计算机桌面通过网络在拼接屏上显示,拼接屏与电脑之间的连接方法
  10. Linux0.11内核详解,linux 内核0.11 学习(一)