着色器Tint

简介

主用减apk体积。如TextView两背景(获焦a、失焦b)。图a、b色外同。UI给两图,适配分辨率则图更多且切换时因重加载bitmap致效率大幅下降。矢量图(SVG)提性能但非绝佳选择。

方案

Tint(apk仅放一图)

使用

两ImageView引同drawable,背景黑。现改其中一ImageView背景为绿。如下:

iv1 = (ImageView) this.findViewById(R.id.iv1);
final Drawable originBitmapDrawable = getResources().getDrawable(R.drawable.ic_account_circle_black_18dp);
iv1.setImageDrawable(tintDrawable(originBitmapDrawable, ColorStateList.valueOf(Color.GREEN)));
问题

改后两背景同绿。

分析

两ImageView引同drawable,系统优化资源把两drawable于内存中拷贝合成一份。如图。改共同变量影响两图。

解决
final Drawable originBitmapDrawable = getResources().getDrawable(R.drawable.
ic_account_circle_black_18dp).mutate();

如此无损谷歌图片内存优化方案。所做仅拿出单独受影响部分内存,没受影响部分仍共享数据。内存另存一些纯标志位类(类似状态值)东西。大部分内存仍公用。

tintDrawable

该方法用来向下兼容。不考虑向下兼容则用系统自带方法即可。

public static Drawable tintDrawable(Drawable drawable, ColorStateList colors) {
    final Drawable wrappedDrawable = DrawableCompat.wrap(drawable);
    DrawableCompat.setTintList(wrappedDrawable, colors);
    return wrappedDrawable;
}

也可如下向下兼容:

public final class TintedBitmapDrawable extends BitmapDrawable {
    private int tint;
    private int alpha;

public TintedBitmapDrawable(final Resources res, final Bitmap bitmap, final int tint) {
    super(res, bitmap);
    this.tint = tint;
    this.alpha = Color.alpha(tint);
}

public TintedBitmapDrawable(final Resources res, final int resId, final int tint) {
    super(res, BitmapFactory.decodeResource(res, resId));
    this.tint = tint;
    this.alpha = Color.alpha(tint);
}

public void setTint(final int tint) {
    this.tint = tint;
    this.alpha = Color.alpha(tint);
}

@Override public void draw(final Canvas canvas) {
    final Paint paint = getPaint();
    if (paint.getColorFilter() == null) {
       paint.setColorFilter(new LightingColorFilter(tint, 0));
       paint.setAlpha(alpha);
    }
    super.draw(canvas);
  }
}

另例

如下改EditText背景色:

et1 = (EditText) this.findViewById(R.id.et);
final Drawable originBitmapDrawable = et1.getBackground();
et1.setBackgroundDrawable(tintDrawable(originBitmapDrawable, ColorStateList.valueOf(Color.GREEN)));
问题

背景色变而光标色没变。xml属性android:textCursorDrawable="@drawable/xxx"可改但如此又增资源文件而不符tint。

思路

android无提供api,如一些private函数需反射调。这里反射获cursorDrawable并着色后反调方法set进去。

解决

EditText实际即TextView。查TextView源码现属性cursorDrawable

// Although these fields are specific to editable text, they are not added to Editor because
// they are defined by the TextView's style and are theme-dependent.
int mCursorDrawableRes;

且查Editor源码,同EditText息息相关:

/**
 * EditText specific data, created on demand when one of the Editor fields is used.
 * See {<a href="http://www.jobbole.com/members/57845349">@link</a> #createEditorIfNeeded()}.
 */
private Editor mEditor;
// 注意该段代码属editor  
final Drawable[] mCursorDrawable = new Drawable[2];

反射:

// 参数即反射所改光标edittext对象
private void invokeEditTextCallCursorDrawable(EditText et) {
    try {
        Field fCursorDrawableRes = TextView.class.getDeclaredField("mCursorDrawableRes");
        // 查源码知该变量非public,需设可访
        fCursorDrawableRes.setAccessible(true);
        // 获editext对象中mCursorDrawableRes属性值,查源码知int
        int mCursorDrawableRes = fCursorDrawableRes.getInt(et);
        // 获mEditor对象后通所获mEditor对象获最终mCursorDrawable之drawable
        Field fEditor = TextView.class.getDeclaredField("mEditor");
        fEditor.setAccessible(true);
        Object editor = fEditor.get(et);
        Class<?> clazz = editor.getClass();
        Field fCursorDrawable = clazz.getDeclaredField("mCursorDrawable");
        fCursorDrawable.setAccessible(true);
        if (mCursorDrawableRes <= 0) {
            return;
        }
        // 到此获默主题下edittext光标小图标之drawable
        Drawable cursorDrawable = et.getContext().getResources().getDrawable(mCursorDrawableRes);
        if (cursorDrawable == null) {
            return;
        }
        // 获drawble并改
        Drawable tintDrawable = tintDrawable(cursorDrawable, ColorStateList.valueOf(Color.GREEN));
        // 前贴mCursorDrawable源码知这是一二维数组,造一全新二维数组
        Drawable[] drawables = new Drawable[]{tintDrawable, tintDrawable};
        // 通反射把该二维数组值放editor中
        fCursorDrawable.set(editor, drawables);
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

snpmyn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值