使用反射方法设置EditText光标颜色

Setting EditText Cursor Color With Reflection Method

我一直在使用反射方法以编程方式设置我的 EditText 的光标颜色,这是我从这个 answer (I also tried this answer) 中找到的。然而,在最近的一些更新之后,记不清具体是什么时候,那个方法不再有效了,我假设 Android 可能改变了 TextView class 中的某些东西。无论如何,有人可以帮我吗? mCursorDrawableResmCursorDrawable 现在是否有新的字段名称,或者整个方法是否无效并且现在需要以其他方式实施?

更新:我刚刚发现这个方法只在AndroidP上失效了,在以前的版本上,它仍然有效。

更新2:我自己解决了问题,如果你也卡住了,请查看答案。

好的,在深入研究 Android Pie 源代码后,我发现 Google 已将 mCursorDrawable 更改为 mDrawableForCursor,并将其类型从 a 更改为二元Drawable数组改为Drawable,所以我在原来反射法的基础上做了一些改动,现在对Android P:

有效
public static void setEditTextCursorColor(EditText editText, int color) {
    try {
        // Get the cursor resource id
        Field field = TextView.class.getDeclaredField("mCursorDrawableRes");
        field.setAccessible(true);
        int drawableResId = field.getInt(editText);

        // Get the editor
        field = TextView.class.getDeclaredField("mEditor");
        field.setAccessible(true);
        Object editor = field.get(editText);

        // Get the drawable and set a color filter
        Drawable drawable = ContextCompat.getDrawable(editText.getContext(), drawableResId);
        drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);

        // Set the drawables
        if(Build.VERSION.SDK_INT >= 28){//set differently in Android P (API 28)
            field = editor.getClass().getDeclaredField("mDrawableForCursor");
            field.setAccessible(true);
            field.set(editor, drawable);
        }else {
            Drawable[] drawables = {drawable, drawable};
            field = editor.getClass().getDeclaredField("mCursorDrawable");
            field.setAccessible(true);
            field.set(editor, drawables);
        }

        //optionally set the "selection handle" color too
        setEditTextHandleColor(editText, color);
    } catch (Exception ignored) {}
}

旁注,我真的希望 Google 可以添加一个 public 方法,如 setCursorDrawable() 或类似的方法,那样会容易得多。

不幸的是,Google 没有公开 xml 属性来着色,或设置方法,即使在兼容性库中也没有这些可绘制对象,因此目前动态设置它们的唯一方法是通过所描述的反射。

但是,您可以在 xml 中设置可绘制对象,如果您只想为现有的 material 设计可绘制对象着色,这可以通过为文本 xml 着色来完成 select handles as they are bitmap drawables,但游标drawable是一个inset drawable,所以必须从源代码重新创建。

使用的绘图是:

R.drawable.abc_text_select_handle_left_mtrl_light
R.drawable.abc_text_select_handle_middle_mtrl_light
R.drawable.abc_text_select_handle_right_mtrl_light
R.drawable.abc_text_cursor_material

您可以创建文本的着色版本 select 像这样处理可绘制对象:

<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/abc_text_select_handle_left_mtrl_light"
    android:tint="@color/my_text_select_handle_color" />

<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/abc_text_select_handle_middle_mtrl_light"
    android:tint="@color/my_text_select_handle_color" />

<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/abc_text_select_handle_right_mtrl_light"
    android:tint="@color/my_text_select_handle_color" />

可以像这样从源代码重新创建光标可绘制对象:

<inset xmlns:android="http://schemas.android.com/apk/res/android"
       android:inset="2dp">
  <shape
      android:tint="@color/my_text_cursor_color"
      android:shape="rectangle">
    <size
        android:height="2dp"
        android:width="2dp" />
    <solid
        android:color="@color/white" />
  </shape>
</inset>

将它们放在 drawables 文件夹中,并在您的 AppCompatEditText xml 定义中引用它们,使用:

android:textCursorDrawable
android:textSelectHandle
android:textSelectHandleLeft
android:textSelectHandleRight

瞧,自定义彩色光标和 select 句柄与默认 material 设计版本完全匹配,避免了反射,因此不会导致警告或错误。