无法将colorFilter应用于文字选取手柄

5

我正在尝试为我的应用添加材料文本选择手柄。我从SDK中获取了中间/右侧/左侧手柄(位图)和文本光标(9-patch)的可绘制对象,并设置:

<item name="android:textSelectHandleLeft">@drawable/text_select_handle_left_mtrl_alpha</item>
<item name="android:textSelectHandleRight">@drawable/text_select_handle_right_mtrl_alpha</item>
<item name="android:textSelectHandle">@drawable/text_select_handle_middle_mtrl_alpha</item>
<item name="android:textCursorDrawable">@drawable/text_cursor_mtrl_alpha</item>

它按预期工作。然而,在棒棒糖中,这些可绘制对象使用android:tint属性以特定颜色进行XML着色,但我无法在API<21上使用。因此,我正在尝试在运行时设置颜色过滤器。

enter image description here

  • 文本光标没有被着色。我认为这可能是由于它是一个9 patch引起的。如何在运行时过滤9-patch可绘制对象?我尝试了所有的PorterDuff.Mode

  • 右/左手柄是黑色的,而中间手柄是白色的。

也就是说,它们都不是我想要的绿色。为什么?

正如您在上面所看到的,我在我的编辑文本下设置了四个ImageView,它们被着色了。

   private void setUpTextCursors() {
        Drawable left = getResources().getDrawable(R.drawable.text_select_handle_left_mtrl_alpha);
        Drawable right = getResources().getDrawable(R.drawable.text_select_handle_right_mtrl_alpha);
        Drawable middle = getResources().getDrawable(R.drawable.text_select_handle_middle_mtrl_alpha);
        Drawable cursor = getResources().getDrawable(R.drawable.text_cursor_mtrl_alpha);
        ColorFilter cf = new PorterDuffColorFilter(mGreenColor, PorterDuff.Mode.SRC_IN);

        /**
        * tint my ImageViews, but no effect on edit text handles
        */
        left.setColorFilter(cf); 
        right.setColorFilter(cf);
        middle.setColorFilter(cf);

        /**
        * no effect whatsoever
        */
        cursor.setColorFilter(cf);
   }

看起来我们在这里有一个9-patch着色问题——因为即使在测试ImageView上也无法通过过滤器,以及一个与应用的过滤器都未被文本选择管理器考虑到的问题。
相关的源代码来自于TextViewclass和我不知道怎么找到的这个Editor隐藏的helper class。花了一些时间研究,但仍然不知道为什么我的过滤器被忽略了。
给 @pskink:让 cursor 成为筛选后的可绘制对象,我可以得到:
<ImageView
    android:id="@id/1"
    android:src="@drawable/cursor_drawable" />

<ImageView 
    android:id="@id/2" />

第一个不会被着色,但如果我调用imageView2.setBackground(cursor),那么它将被着色。 同样,如果我有
<item name="android:textSelectHandle">@drawable/cursor_drawable</item>

这会影响编辑选择(因为我覆盖了默认光标),但它没有着色。

游标.getPaint() 返回什么? - pskink
@pskink 您是正确的,我有一个空的 mPaint 值。为什么?除此之外,过滤器在处理句柄时应用得很好,正如您在我的测试视图中所看到的那样。问题在于选择管理器接受可绘制对象但忽略我的过滤器。我在末尾添加了一些源代码链接。 - natario
我没有深入研究,但似乎是一个错误,请先调用getPaint,然后再调用setColorFilter,这样会改变什么吗? - pskink
@psking 不错的尝试 - 我使用非空的 mPaint 进入了 setColorFilter,并使用非空的 mColorFilter 退出。但是,光标和测试图像视图仍然是白色的。 - natario
在draw(Canvas)中设置一个断点,然后查看为什么你的颜色过滤器没有应用。 - pskink
显示剩余12条评论
2个回答

3

您需要覆盖Activity使用的默认资源:

// your activity source file
Resources res;

@Override
public Resources getResources() {
    if (res == null) {
        res = new TintResources(super.getResources());
    }
    return res;
}

自定义资源类将覆盖getDrawable()方法,因此您可以拦截创建Drawable并设置颜色过滤器,例如:
class TintResources extends Resources {

    public TintResources(Resources resources) {
        super(resources.getAssets(), resources.getDisplayMetrics(), resources.getConfiguration());
    }

    @Override
    public Drawable getDrawable(int id) throws NotFoundException {
        Drawable d = super.getDrawable(id);
        if (id == R.drawable.text_cursor_material) {
            // setup @drawable/text_cursor_material
            d.setColorFilter(0xff00aa00, PorterDuff.Mode.SRC_IN);
        }
        return d;
    }
}

同样的方法,您可以设置其他可绘制物(@drawable/text_select_handle_*_material),请注意您需要采用此方式而不是直接方式,因为EditText没有访问这些可绘制物的getter方法。


出于好奇,检查 res == null(即仅实例化 TintResources 一次)有什么意义?我在这里错过了一些 Java 基础知识。我只会简单地调用 getResources() { return new TintResources() } - natario
在那里添加Log.d并查看它被调用的频率,非常非常多次...但是如果您不关心,可以跳过这些额外的步骤并始终返回新的TintResources。 - pskink

1
这只是一个部分答案,我们也可以认为它相当糟糕,因为它只是一个解决办法。我能够通过指向XML文件而不是原始png文件来加载仅句柄(即BitmapDrawables)到edittext(或任何其他选择内容)中。也就是说,我设置了:
<item name="android:textSelectHandleLeft">@drawable/text_select_handle_left_material</item>
<item name="android:textSelectHandleRight">@drawable/text_select_handle_right_material</item>
<item name="android:textSelectHandle">@drawable/text_select_handle_middle_material</item>
<item name="android:textCursorDrawable">@drawable/text_cursor_material</item>

这里是像这样的XML可绘制对象:

<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/text_select_handle_left_mtrl_alpha" />

or

<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/text_cursor_mtrl_alpha" />

如果我筛选这些可绘制对象,我发现它们在视图和选择中都被染色了。因此,我修改了我的方法如下:

private void setUpTextCursors() {
    ColorFilter cf = new PorterDuffColorFilter(mColorControlActivated, PorterDuff.Mode.SRC_IN);
    BitmapDrawable left = (BitmapDrawable) getResources().getDrawable(R.drawable.text_select_handle_left_material);
    BitmapDrawable middle = (BitmapDrawable) getResources().getDrawable(R.drawable.text_select_handle_middle_material);
    BitmapDrawable right = (BitmapDrawable) getResources().getDrawable(R.drawable.text_select_handle_right_material);
    // NinePatchDrawable cursor = (NinePatchDrawable) getResources().getDrawable(R.drawable.text_cursor_material);
    left.setColorFilter(cf);
    right.setColorFilter(cf);
    middle.setColorFilter(cf);
    // cursor.setColorFilter(cf); this does not work: cursor still white!
}

然而,虽然这对于leftrightmiddle有效,但是9-patch cursor仍然存在问题,因为我无法使其着色。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接