CardView是android L的新特性。卡片式容器,其特色是圆角和阴影效果,给扁平化元素增长了立体感。其实就是一种Material Design设计理念的代码实现。android
cardBackgroundColor 整个卡片背景颜色
cardCornerRadius 卡片边角半径
cardElevation 卡片的阴影实际宽度,你们都知道 Material Design 就是引入了材质厚度的概念。实际就是经过投射阴影的原理实现这种视觉效果。
cardMaxElevation 阴影区域宽度,与实际上的padding有关。
cardUseCompatPadding 5.0以上有效,true,padding=阴影区域宽度+contentPadding
cardPreventCornerOverlap 设置是否圆角重叠。
contentPadding cardview内容区边缘和其子view边缘的距离。padding=contentpadding+阴影宽度。setpadding在cardview里失效。
contentPaddingLeft 与上面同理
contentPaddingTop 与上面同理
contentPaddingRight 与上面同理
contentPaddingBottom 与上面同理canvas
public class CardView extends FrameLayout implements CardViewDelegate { private static final CardViewImpl IMPL; ... }
继承至frameLayout,实现接口CardViewDelegate,实现cardview的 效果的处理逻辑就是在CardViewDelegate和CardViewImpl中实现得。
CardViewJellybeanMr1 21>api>=17实例化它
CardViewEclairMr1 api<17实例化它
CardViewApi21 api>=21实例化它
都是cardview的阴影和边角绘制工具,都继承CardViewImpl
CardViewJellybeanMr1 extends CardViewEclairMr1,惟一差异就是在初始化方法initStatic()中建立边框(RoundRectDrawableWithShadow)时,对canvas的方法调用的兼容。通俗点说就是对这个边框的画法不一样。
android L对API的更新后,view自己就具有了绘制阴影的能力。view在绘制时,添加了对view背景的绘制drawBackground(Canvas canvas),其中引入的RenderNode是对绘制的信息以及本地接口进行封装,包括setElevation设置的elevation值最终也是经过它来调用本地接口进行绘制
cardview出现的目的,能够说是一个为了圆角和阴影效果向后兼容。api
上面说了,为了兼容,cardview的各类属性设置都是经过CardViewImpl来实现。但为了解耦,CardViewDelegate就像它字面意思同样,被CardView委托,目的是为了向CardViewImpl提供必要的对象,好比背景Drawable。ide
它的实现并无重写onLayout,那么他的布局方式跟framelayout同样。但onMeasure方法被重写:工具
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { if (IMPL instanceof CardViewApi21 == false) { final int widthMode = MeasureSpec.getMode(widthMeasureSpec); switch (widthMode) { case MeasureSpec.EXACTLY: case MeasureSpec.AT_MOST: final int minWidth = (int) Math.ceil(IMPL.getMinWidth(this)); widthMeasureSpec = MeasureSpec.makeMeasureSpec(Math.max(minWidth, MeasureSpec.getSize(widthMeasureSpec)), widthMode); break; } final int heightMode = MeasureSpec.getMode(heightMeasureSpec); switch (heightMode) { case MeasureSpec.EXACTLY: case MeasureSpec.AT_MOST: final int minHeight = (int) Math.ceil(IMPL.getMinHeight(this)); heightMeasureSpec = MeasureSpec.makeMeasureSpec(Math.max(minHeight, MeasureSpec.getSize(heightMeasureSpec)), heightMode); break; } super.onMeasure(widthMeasureSpec, heightMeasureSpec); } else { super.onMeasure(widthMeasureSpec, heightMeasureSpec); } }
其实能够看出,5.0及以上,尺寸的计算方式没变,可是5.0如下从新计算了尺寸。形成的结果是,5.0如下CardView的父容器设置wrap_content的时候,CardView即使没有子视图且它也是wrap_content,它也占据必定尺寸,由于有显示阴影和圆角边框;但在android L它的尺寸就会变成0,看不到cardview以及其阴影效果。布局
5.0如下版本,CardView的最小尺寸取决于IMPL.getMinWIdth(this),实际上调用的RoundRectDrawableWithShadow的getMinWidth:this
float getMinWidth() { final float content = 2 * Math.max(mRawMaxShadowSize, mCornerRadius + mInsetShadow + mRawMaxShadowSize / 2); return content + (mRawMaxShadowSize + mInsetShadow) * 2; }
换言之,android L的CardView大小跟framelayout同理,但android L之前的版本,它的大小还跟设置的elevation和圆角半径有关。须要注意!设计
cardUseCompatPadding在5.0如下版本设置没有效果,5.0以上若是设置为false,阴影区域宽度不会加入到实际padding中。
cardElevation > cardMaxElevation时,以cardElevation为准,且阴影区域宽度=阴影实际宽度。
cardPreventCornerOverlap 当边角过大时,这个设置可能也会失效,以下图,设置了边角为300dp,可能实际宽度也就400dp左右code