返回介绍

1. fab 的自定义属性、背景着色相关

发布于 2024-12-23 22:29:23 字数 5107 浏览 0 评论 0 收藏 0

从构造器开始:

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文