<androidx.cardview.widget.CardView
android:id="@+id/actionOneCv"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:foreground="?android:attr/selectableItemBackground"
app:cardCornerRadius="0dp"
app:cardElevation="0dp"/>
常使用上述的寫法來實現(xiàn)一個button樣式舆逃。
問題一:
如果將其放入在一個dialog的bottom位置作為點擊按鈕凹嘲,dialog的background
設置了圓角堂飞,但是顯示button一角卻還是直角昼接。
問題二:
此時dialog更改bg顏色爽篷,發(fā)現(xiàn)CardView區(qū)域還是白色。
針對問題一慢睡,當然可以更改CardView來手動設置某一部分是圓角逐工。
但兩個問題的癥結其實都是同一個點,那就是:
設置水波紋foreground的CardView默認背景就是白色
解決方案:將默認背景改為透明漂辐,則就能顯示出dialog底背景的樣式了泪喊。
<androidx.cardview.widget.CardView
android:id="@+id/actionOneCv"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
app:cardBackgroundColor="@color/transparent"
android:foreground="?android:attr/selectableItemBackground"
app:cardCornerRadius="0dp"
app:cardElevation="0dp"/>
可以看到此處是設置app:cardBackgroundColor="@color/transparent"
.
問題來了,上述的方法只能設置color髓涯,如果要設置drawable該怎么辦袒啼?
其實解決方案很簡單:CardView
本身是繼承自FrameLayout
的,這就意味著它是可以包裹內容的,里面包裹其它控件(如ImageView
)瘤泪。通過包裹的控件來實現(xiàn)有drawable的背景即可灶泵。
那么又有問題了,既然CardView繼承自FrameLayout对途,這就說明其是可以設置Background的赦邻。但為什么設置后卻顯示不出來呢?
這個就涉及到整個View的構造流程了:
public CardView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//省略屬性獲取
IMPL.initialize(mCardViewDelegate, context, backgroundColor, radius,
elevation, maxElevation);
}
初始化View進入構造方法实檀,會進行IMPL.initialize
方法的調用惶洲。這個IMPL是什么?
private static final CardViewImpl IMPL;
static {
if (Build.VERSION.SDK_INT >= 21) {
IMPL = new CardViewApi21Impl();
} else if (Build.VERSION.SDK_INT >= 17) {
IMPL = new CardViewApi17Impl();
} else {
IMPL = new CardViewBaseImpl();
}
IMPL.initStatic();
}
IMPL是CardView的實現(xiàn)類膳犹,不同的版本有不同的實現(xiàn)恬吕。此處進入CardViewApi21Impl里面看看initialize
實現(xiàn)。
@Override
public void initialize(CardViewDelegate cardView, Context context,
ColorStateList backgroundColor, float radius, float elevation, float maxElevation) {
final RoundRectDrawable background = new RoundRectDrawable(backgroundColor, radius);
cardView.setCardBackground(background);
View view = cardView.getCardView();
view.setClipToOutline(true);
view.setElevation(elevation);
setMaxElevation(cardView, maxElevation);
}
可以發(fā)現(xiàn)在這里面進行了cardView.setCardBackground
調用须床,而background是根據(jù)設置的
backgroundColor = a.getColorStateList(R.styleable.CardView_cardBackgroundColor);
賦值RoundRectDrawable生成而來铐料。
cardView.setCardBackground(background);
中的CardView是CardViewDelegate
,它是一個接口豺旬,所以也要看它的實現(xiàn)類钠惩。在CardView類中可以找到:
private final CardViewDelegate mCardViewDelegate = new CardViewDelegate() {
private Drawable mCardBackground;
@Override
public void setCardBackground(Drawable drawable) {
mCardBackground = drawable;
setBackgroundDrawable(drawable);
}
//...
}
而上面的setBackgroundDrawable
則是進入到了View層面了。
至此已經(jīng)很清楚了族阅,因為initialize
在父類(FrameLayout)的構造方法之后調用篓跛,導致最終設置的setBackgroundDrawable
會始終覆蓋父類的該方法實現(xiàn)。
說到底坦刀,就是個實現(xiàn)的先后覆蓋問題愧沟。