Android开发小技巧-动态设置Drawable与Tint

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第17天,点击查看活动详情

动态设置Drawable与Tint

本文讲一下ImageView设置Drawable设置tint改变颜色,以及代码中动态的给Drawable设置Tint, 以及 TextView 动态的设置 Drawable,以及它们的结合 给TextView 动态设置一个动态设置了Tint的Drawable。

有点绕,看看Demo示例,很简单。

一、Tint的使用

项目的图片如果是一样的,只是颜色不同,我们可以使用tint来改变颜色。可以减少Apk的大小

        <ImageView
            android:layout_width="@dimen/d_28dp"
            android:layout_height="@dimen/d_28dp"
            android:src="@mipmap/jobs_tips_date_icon"
            app:tint="@color/colorAccent" />

这样显示的图片就变成了指定的红色了。

这里高版本只能使用 app 前缀, 不支持android 前缀了。也是为了兼容低版本。用法没有改变。

1.1 动态的设置Tint

动态的在 Activity 代码中设置 Tint 如何使用:

获取到Drawable,然后给Drawable设置Tint颜色即可

    getDrawable(R.mipmap.jobs_tips_date_icon)?.let {
            DrawableCompat.setTint(it, Color.GREEN)
            mBinding.ivTint.setImageDrawable(it)
        }

但是如果我想要状态切换颜色怎么办?未选中是橙色,选中是蓝色,你这个不能设置drawable-selector啊。

1.2 动态的设置TintList

我们可以使用color-selector来实现状态的切换:

     getDrawable(R.mipmap.jobs_tips_date_icon)?.let {
            DrawableCompat.setTintList(it, resources.getColorStateList(R.color.full_tab_color_selector))
            mBinding.ivTint2.setImageDrawable(it)
        }

     mBinding.ivTint2.click { it.isSelected = true }

注意这里的方法是 setTintList 设置的是颜色组了。

我们看看效果:

可以看到第三个图片是橙色的,点击切换状态即可变为蓝色

很简单的就能实现切换,如果图片本身没有变化只是颜色的变化,我们可以使用这种方法,少导入一些图片,对内存也有一定的优化。

二、Left / Right Drawable的使用

       <TextView
            android:id="@+id/tv_center_text"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="@color/divider_color"
            android:drawablePadding="@dimen/d_5dp"
            android:drawableLeft="@mipmap/jobs_tips_date_icon"
            android:gravity="center"
            android:text="我是居中文本" />

这个在xml中设置,相信大家都会使用了,在代码中使用也很简单:

2.1 动态的设置setCompoundDrawables

如下,如果需要置顶我们就设置一个置顶icon,如果无需置顶,我们全部清除即可。

        if (item.topping == 1) {
                Drawable drawable = CommUtils.getDrawable(R.drawable.job_featured);
                drawable.setBounds(0, 0, drawable.getMinimumWidth(), drawable.getMinimumHeight());
                tv_job_title.setCompoundDrawables(null, null, drawable, null);
            } else {
                tv_job_title.setCompoundDrawables(null, null, null, null);
            }

如果我们不使用宽度自适应,用 padding 撑开宽度。 而是固定宽度或者matchParent,我们设置drawable则是这样的效果:

2.2 leftDrawable居中

这种情况下如果我们想要图片与文本居中显示,我们就需要使用自定义View的方式:

public class LeftDrawableCenterTextView extends AppCompatTextView {

    public LeftDrawableCenterTextView(Context context) {
        super(context);
    }

    public LeftDrawableCenterTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public LeftDrawableCenterTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Drawable[] drawables = getCompoundDrawables();
        Drawable drawableLeft = drawables[0];
        if (drawableLeft != null) {
            int drawableWith = drawableLeft.getIntrinsicWidth();
            int drawablePadding = getCompoundDrawablePadding();
            int textWith = (int) getPaint().measureText(getText().toString());
            int bodyWith = drawableWith + drawablePadding + textWith;
            canvas.translate((getWidth() - bodyWith) / 2, 0);
        }

        super.onDraw(canvas);
    }
}

我们修改xml指定为我们的textView

       <xxx.LeftDrawableCenterTextView
            android:id="@+id/tv_center_text"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:background="@color/divider_color"
            android:drawablePadding="@dimen/d_5dp"
            android:gravity="center"
            android:text="我是居中文本" />

我们动态的设置或者在xml里设置drawable都是可以的:

     //手动的设置leftDrawable
        ContextCompat.getDrawable(this, R.mipmap.jobs_tips_date_icon)?.let {
            it.setBounds(0, 0, it.minimumWidth, it.minimumHeight)
            mBinding.tvCenterText.apply {
                setCompoundDrawables(it, null, null, null)
                gravity = Gravity.CENTER_VERTICAL
            }
        }

效果:

2.3 rightDrawable居中

看到自定义View的名字就知道,专门为 leftDrawable 设置的。如果是rightDrawable 那么计算的方式会有所不同:

public class RightDrawableCenterTextView extends AppCompatTextView {

    public RightDrawableCenterTextView(Context context) {
        super(context);
    }

    public RightDrawableCenterTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public RightDrawableCenterTextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    @Override
    protected void onDraw(Canvas canvas) {
        Drawable[] drawables = getCompoundDrawables();
        Drawable drawable = drawables[2];
        if (drawable != null) {
            float textWidth = getPaint().measureText(getText().toString());
            int drawablePadding = getCompoundDrawablePadding();
            int drawableWidth = drawable.getMinimumWidth();
            float bodyWidth = textWidth + drawableWidth + drawablePadding + getPaddingLeft() + getPaddingRight();
            canvas.translate((bodyWidth - getWidth()) / 2, 0);
        }
        super.onDraw(canvas);
    }
}

同样的用法,我们可以在java或者在xml里设置drawable都是可以的:

  //手动的设置rightDrawable
        ContextCompat.getDrawable(this, R.mipmap.jobs_tips_date_icon)?.let {
            it.setBounds(0, 0, it.minimumWidth, it.minimumHeight)
            mBinding.tvCenterText.apply {
                setCompoundDrawables(null, null, it, null)
                gravity = Gravity.CENTER_VERTICAL or Gravity.RIGHT
            }
        }

效果:

三、动态Drawable + 动态Tint

我们可以看到动态在Java代码中给 TextView 设置了 drawable 对象,那么在drawable 对象赋值给 TextView 之前,我们是不是可以对drawable设置tint呢?

试试看效果,代码如下:

        //手动的设置rightDrawable
        ContextCompat.getDrawable(this, R.mipmap.jobs_tips_date_icon)?.let {
            it.setBounds(0, 0, it.minimumWidth, it.minimumHeight)
            DrawableCompat.setTint(it, Color.GREEN)
            mBinding.tvCenterText.apply {
                setCompoundDrawables(null, null, it, null)
                gravity = Gravity.CENTER_VERTICAL or Gravity.RIGHT
            }
        }

可以看到效果确实是变绿色了:

设置颜色状态选择器能不能生效?

        //手动的设置rightDrawable
        ContextCompat.getDrawable(this, R.mipmap.jobs_tips_date_icon)?.let {
            it.setBounds(0, 0, it.minimumWidth, it.minimumHeight)
            DrawableCompat.setTintList(it, resources.getColorStateList(R.color.full_tab_color_selector))
            mBinding.tvCenterText.apply {
                setCompoundDrawables(null, null, it, null)
                gravity = Gravity.CENTER_VERTICAL or Gravity.RIGHT
                click { it.isSelected = true }
            }
        }

效果:

点击之后:

总结

如果图片没有变化,不管是状态切换,还是手动的设置drawableLeft drawableRight 都可以使用tint,我们就无需找设计师要多套图片了。

需要注意的一点是,我们在实际开发过程中,需要注意设置Tint之后是否需要清除它Tint属性。

最这也算是一个很简单也很重要的小知识,如果有更好的办法,欢迎大家讨论。

代码都已在文中贴出,如果想直接看Demo效果,点击查看源码

到此完结。

猜你喜欢

转载自juejin.im/post/7114571524526309390