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