无法将 colorFilter 应用于文本选择句柄

Can't apply a colorFilter to text selection handles

我正在尝试为我的应用程序添加 material 文本选择句柄。我从 SDK 获得了 middle/right/left 句柄(位图)和文本光标(9 补丁)的可绘制对象,并设置:

<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>

它按预期工作。但是,在 Lollipop 中,这些可绘制对象使用 android:tint 属性在 XML 中使用特定颜色着色,我无法在 API<21 上使用该属性。所以我试图在运行时设置一个颜色过滤器。

也就是说,没有一个像我想要的那样是绿色的。为什么?

正如您在上面看到的,我在我的编辑文本下方设置了四个 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 补丁着色问题 - 因为即使在测试 ImageViews 上过滤器也会失败 - 以及与文本选择管理器考虑应用过滤器的 none 个事实相关的问题.

相关源代码来自 TextView class and from this Editor hidden 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>

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

这只是部分答案,我们也可以认为它很糟糕,因为它是一种解决方法。通过指向 XML 文件而不是原始 png 文件,我能够仅加载编辑文本(或任何其他选择内容)内的句柄(即 BitmapDrawables)。 IE。我设置:

<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" />

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

如果我过滤这些可绘制对象,我发现它们在视图 和选择中 both 着色。所以我改变了我的方法:

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 补丁 cursor 仍然存在问题,因为我不能染上颜色。

您需要覆盖 Activity:

使用的默认资源
// your activity source file
Resources res;

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

自定义资源 class 将覆盖 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;
    }
}

与设置其他 Drawables (@drawable/text_select_handle_*_material) 的方式相同,请注意,您需要的不是直接方式,因为 EditText 没有 getter 访问这些 Drawables 的方法