- 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 就呈现出我们想要的颜色啦。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论