- CompoundButton 源码分析
- LinearLayout 源码分析
- SearchView 源码解析
- LruCache 源码解析
- ViewDragHelper 源码解析
- BottomSheets 源码解析
- Media Player 源码分析
- NavigationView 源码解析
- Service 源码解析
- Binder 源码分析
- Android 应用 Preference 相关及源码浅析 SharePreferences 篇
- ScrollView 源码解析
- Handler 源码解析
- NestedScrollView 源码解析
- SQLiteOpenHelper/SQLiteDatabase/Cursor 源码解析
- Bundle 源码解析
- LocalBroadcastManager 源码解析
- Toast 源码解析
- TextInputLayout
- LayoutInflater 和 LayoutInflaterCompat 源码解析
- TextView 源码解析
- NestedScrolling 事件机制源码解析
- ViewGroup 源码解析
- StaticLayout 源码分析
- AtomicFile 源码解析
- AtomicFile 源码解析
- Spannable 源码分析
- Notification 之 Android 5.0 实现原理
- CoordinatorLayout 源码分析
- Scroller 源码解析
- SwipeRefreshLayout 源码分析
- FloatingActionButton 源码解析
- AsyncTask 源码分析
- TabLayout 源码解析
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
1. fab 的自定义属性、背景着色相关
从构造器开始:
public FloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
//检查是否使用 Theme.Appcompat 主题
ThemeUtils.checkAppCompatTheme(context);
//拿到自定义属性并赋值
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.FloatingActionButton, defStyleAttr,
R.style.Widget_Design_FloatingActionButton);
...
a.recycle();
final int maxImageSize = (int) getResources().getDimension(R.dimen.design_fab_image_size);
mImagePadding = (getSizeDimension() - maxImageSize) / 2;
//背景着色
getImpl().setBackgroundDrawable(mBackgroundTint, mBackgroundTintMode,
mRippleColor, mBorderWidth);
//绘制阴影
getImpl().setElevation(elevation);
...
}构造器中主要是拿到用户设置的自定义属性,比如着色、波纹颜色、大小等等,一共有以下几个属性可以定义。
<declare-styleable name="FloatingActionButton"> <attr name="backgroundTint"/> <attr name="backgroundTintMode"/> <attr format="color" name="rippleColor"/> <attr name="fabSize"> <enum name="normal" value="0"/> <enum name="mini" value="1"/> </attr> <attr name="elevation"/> <attr format="dimension" name="pressedTranslationZ"/> <attr format="dimension" name="borderWidth"/> <attr format="boolean" name="useCompatPadding"/> </declare-styleable>
属性的默认值定义如下:
<style name="Widget.Design.FloatingActionButton" parent="android:Widget">
<item name="android:background">@drawable/design_fab_background</item>
<item name="backgroundTint">?attr/colorAccent</item>
<item name="fabSize">normal</item>
<item name="elevation">@dimen/design_fab_elevation</item>
<item name="pressedTranslationZ">@dimen/design_fab_translation_z_pressed</item>
<item name="rippleColor">?attr/colorControlHighlight</item>
<item name="borderWidth">@dimen/design_fab_border_width</item>
</style>需要注意的是 android:background 属性,这里指定了 background 为 design_fab_background ,并且不允许改变:
@Override
public void setBackgroundDrawable(Drawable background) {
Log.i(LOG_TAG, "Setting a custom background is not supported.");
}那么我们来看下这个 background 长啥样:
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@android:color/white" />
</shape>很显然,fab 的形状固定为圆形都是因为这个 background。那么这里指定了背景色为白色,那是不是 fab 只能是白色背景呢?当然不是,还有我们牛逼的 backgroundTint(即背景着色),tint 是 android 5.x 引进的一个新特性,可以动态地给 drawable 资源着色,其原理就是通过给控件设置 colorFilter:
drawable.java
public void setColorFilter(@ColorInt int color, @NonNull PorterDuff.Mode mode) {
setColorFilter(new PorterDuffColorFilter(color, mode));
}默认的着色模式为 SRC_IN(取交集、显示上层,故底层白色会被忽略):
static final PorterDuff.Mode DEFAULT_TINT_MODE = PorterDuff.Mode.SRC_IN;
在 fab 构造的时候,会指定着色为 ?attr/colorAccent ,即当前主题的 colorAccent 属性值。 然后执行如下代码,进行着色。
getImpl().setBackgroundDrawable(mBackgroundTint, mBackgroundTintMode,
mRippleColor, mBorderWidth);因为不同版本间的实现略有不同,所以这里会根据不同版本创建不同的 FloatingActionButtonImpl 实现类:
private FloatingActionButtonImpl createImpl() {
final int sdk = Build.VERSION.SDK_INT;
if (sdk >= 21) {
return new FloatingActionButtonLollipop(this, new ShadowDelegateImpl());
} else if (sdk >= 14) {
return new FloatingActionButtonIcs(this, new ShadowDelegateImpl());
} else {
return new FloatingActionButtonEclairMr1(this, new ShadowDelegateImpl());
}
}以 5.x 为例,其 setBackgroundDrawable 实现代码如下:
先创建着色的背景 drawable。
GradientDrawable createShapeDrawable() {
GradientDrawable d = new GradientDrawable();
d.setShape(GradientDrawable.OVAL);
d.setColor(Color.WHITE);
return d;
}再对此 drawable 设置 tint:
@Override
void setBackgroundDrawable(ColorStateList backgroundTint,
PorterDuff.Mode backgroundTintMode, int rippleColor, int borderWidth) {
// Now we need to tint the shape background with the tint
mShapeDrawable = DrawableCompat.wrap(createShapeDrawable());
//着色,这里会其实就是设置了下 colorFilter
DrawableCompat.setTintList(mShapeDrawable, backgroundTint);
if (backgroundTintMode != null) {
DrawableCompat.setTintMode(mShapeDrawable, backgroundTintMode);
}
final Drawable rippleContent;
if (borderWidth > 0) {
mBorderDrawable = createBorderDrawable(borderWidth, backgroundTint);
rippleContent = new LayerDrawable(new Drawable[]{mBorderDrawable, mShapeDrawable});
} else {
mBorderDrawable = null;
rippleContent = mShapeDrawable;
}
mRippleDrawable = new RippleDrawable(ColorStateList.valueOf(rippleColor),
rippleContent, null);
mContentBackground = mRippleDrawable;
mShadowViewDelegate.setBackgroundDrawable(mRippleDrawable);
}经过着色,fab 就呈现出我们想要的颜色啦。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论