最近在項目中使用了FloatingActionButton ,但是為了讓UI看起來留白不是那么多你踩,需要對FloatingActionButton 進行自定義大小虑乖。
根據(jù)官方文檔的說明歧斟,FloatingActionButton 僅僅支持設(shè)置app:fabSize="normal"來改變fab的大小,并且這個fabSize的大小提供了三個可選項(normal剃氧,mini和auto)來設(shè)置,可以在布局里設(shè)置也可以在代碼里調(diào)用setSize方法進行設(shè)置阻星。
這里一開始是想到通過在布局里改變layout_width和layout_height來改變控件的大小的朋鞍,但是設(shè)置之后(兩者均設(shè)置為100dp,fabSize設(shè)置為normal),效果如下所示:
并且當設(shè)置了fab的固定寬高再來改變它的fabSize屬性(改為mini或auto)時滥酥,效果會是fab的圖標被撐的很大更舞,甚至邊緣都看不到了,顯然這樣通過固定fab的寬高屬性來改變其大小是行不通的坎吻。
翻閱FloatingActionButton的源碼缆蝉,其第三個構(gòu)造函數(shù)如下
public FloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
ThemeUtils.checkAppCompatTheme(context);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.FloatingActionButton, defStyleAttr,
R.style.Widget_Design_FloatingActionButton);
mBackgroundTint = a.getColorStateList(R.styleable.FloatingActionButton_backgroundTint);
mBackgroundTintMode = ViewUtils.parseTintMode(a.getInt(
R.styleable.FloatingActionButton_backgroundTintMode, -1), null);
mRippleColor = a.getColor(R.styleable.FloatingActionButton_rippleColor, 0);
mSize = a.getInt(R.styleable.FloatingActionButton_fabSize, SIZE_AUTO);
mBorderWidth = a.getDimensionPixelSize(R.styleable.FloatingActionButton_borderWidth, 0);
final float elevation = a.getDimension(R.styleable.FloatingActionButton_elevation, 0f);
final float pressedTranslationZ = a.getDimension(
R.styleable.FloatingActionButton_pressedTranslationZ, 0f);
mCompatPadding = a.getBoolean(R.styleable.FloatingActionButton_useCompatPadding, false);
a.recycle();
mImageHelper = new AppCompatImageHelper(this);
mImageHelper.loadFromAttributes(attrs, defStyleAttr);
mMaxImageSize = (int) getResources().getDimension(R.dimen.design_fab_image_size);
getImpl().setBackgroundDrawable(mBackgroundTint, mBackgroundTintMode,
mRippleColor, mBorderWidth);
getImpl().setElevation(elevation);
getImpl().setPressedTranslationZ(pressedTranslationZ);
}
都是讀取屬性來設(shè)置一些自定義屬性,看到最后三行瘦真,發(fā)現(xiàn)getImpl方法的調(diào)用刊头,它的返回值是FloatingActionButtonImpl,原來fab都是通過FloatingActionButtonImpl來實現(xiàn)其自定義屬性的吗氏,找到getImpl這個方法芽偏,源碼如下:
private FloatingActionButtonImpl getImpl() {
if (mImpl == null) {
mImpl = createImpl();
}
return mImpl;
}
private FloatingActionButtonImpl createImpl() {
final int sdk = Build.VERSION.SDK_INT;
if (sdk >= 21) {
return new FloatingActionButtonLollipop(this, new ShadowDelegateImpl(),
ViewUtils.DEFAULT_ANIMATOR_CREATOR);
} else if (sdk >= 14) {
return new FloatingActionButtonIcs(this, new ShadowDelegateImpl(),
ViewUtils.DEFAULT_ANIMATOR_CREATOR);
} else {
return new FloatingActionButtonGingerbread(this, new ShadowDelegateImpl(),
ViewUtils.DEFAULT_ANIMATOR_CREATOR);
}
}
上面創(chuàng)建FloatingActionButtonImpl每種情況都傳遞了ShadowDelegateImpl的一個實例,說明這個類對創(chuàng)建FloatingActionButtonImpl很重要弦讽,往下看這個類的源碼污尉,如下所示:
private class ShadowDelegateImpl implements ShadowViewDelegate {
ShadowDelegateImpl() {
}
@Override
public float getRadius() {
return getSizeDimension() / 2f;
}
@Override
public void setShadowPadding(int left, int top, int right, int bottom) {
mShadowPadding.set(left, top, right, bottom);
setPadding(left + mImagePadding, top + mImagePadding,
right + mImagePadding, bottom + mImagePadding);
}
@Override
public void setBackgroundDrawable(Drawable background) {
FloatingActionButton.super.setBackgroundDrawable(background);
}
@Override
public boolean isCompatPaddingEnabled() {
return mCompatPadding;
}
}
這個類里有一個getRadius方法,字面意思理解就是獲取半徑的往产,終于柳暗花明被碗,原來fab的大小(即半徑)是這個方法來獲取的仿村,可以看到它調(diào)用了getSizeDimension锐朴,下面看這個getSizeDimension方法,源碼如下:
int getSizeDimension() {
return getSizeDimension(mSize);
}
private int getSizeDimension(@Size final int size) {
final Resources res = getResources();
switch (size) {
case SIZE_AUTO:
// If we're set to auto, grab the size from resources and refresh
final int width = ConfigurationHelper.getScreenWidthDp(res);
final int height = ConfigurationHelper.getScreenHeightDp(res);
return Math.max(width, height) < AUTO_MINI_LARGEST_SCREEN_WIDTH
? getSizeDimension(SIZE_MINI)
: getSizeDimension(SIZE_NORMAL);
case SIZE_MINI:
return res.getDimensionPixelSize(R.dimen.design_fab_size_mini);
case SIZE_NORMAL:
default:
return res.getDimensionPixelSize(R.dimen.design_fab_size_normal);
}
}
原來這里google做的控件也是通過獲取資源文件dimens.xml來獲取dimen值的(廢話蔼囊,當然是了)焚志。終于看到這里,我才恍然大悟畏鼓,我可以通過自定義這個design_fab_size_normal來實現(xiàn)覆蓋默認的dimen值呀(因為我的布局里是設(shè)置fabSize為normal的)酱酬,自定義代碼如下所示:
<dimen name="design_fab_size_normal" tools:ignore="PrivateResource">80dp</dimen>
這樣即完美搞定我的fab自定義大小的需求。上張效果圖云矫,如下所示:
和之前那個設(shè)置fab的固定寬高的效果比好多了膳沽。