【问题标题】:Setting EditText Cursor Color With Reflection Method使用反射方法设置 EditText 光标颜色
【发布时间】:2018-09-29 01:27:40
【问题描述】:

我一直在使用反射方法以编程方式设置我的EditText 的光标颜色,这是我从这个answer 找到的(我也试过这个answer)。但是,在最近的一些更新之后,不记得确切的时间,该方法不再有效,我认为 Android 可能已经更改了 TextView 类中的某些内容。无论如何,有人可以帮我解决这个问题吗? mCursorDrawableResmCursorDrawable 现在是否有新的字段名称,或者整个方法无效并且现在需要以其他方式实现?

更新:我刚刚发现此方法仅在 Android P 上停止工作,在以前的版本上,它仍然有效。

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

【问题讨论】:

  • 有人可以解释一下否决票吗?我做错了什么?

标签: java android reflection android-edittext textview


【解决方案1】:

好的,在深入Android Pie Source Code之后,我发现Google已经将mCursorDrawable更改为mDrawableForCursor,并将其类型从两个元素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 可以添加一个像 setCursorDrawable() 或类似的公共方法,这样会容易得多。

【讨论】:

  • 感谢您的回答!但是访问像mDrawableForCursor 这样的字段可能会导致问题due to restrictions on non-SDK interfaces。目前,此修复程序在我的 Android 9 模拟器上显示“检测到 API 兼容性问题(请访问 g.co/dev/appcompat 了解更多信息)”错误。
  • 是的,我知道,我也收到了这个警告,但我找不到任何其他方法来做到这一点。所以我想在 Android 团队决定对此采取措施或其他人找到更好的解决方案之前,我们必须坚持这种方式。
  • 你做的很棒!我也想看看android源码...
  • 还有其他解决方案吗?我也收到了这个警告,访问这个隐藏字段之王让我收到警告“访问隐藏字段 Landroid/widget/Editor;->mDrawableForCursor:Landroid/graphics/drawable/Drawable;(暗灰名单,反射)”:(
【解决方案2】:

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

但是,您可以在 xml 中设置可绘制对象,如果您只想为现有的材料设计可绘制对象着色,可以通过为文本选择句柄着色 xml 来完成,因为它们是位图可绘制对象,但光标可绘制对象是插图可绘制,因此必须从源代码重新创建。

使用的drawables是:

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

您可以像这样创建文本选择句柄可绘制对象的着色版本:

<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

瞧,自定义颜色光标和选择手柄与默认材料设计版本完全匹配,避免反射,因此不会导致警告或错误。

【讨论】:

  • 这是 XML 方式,我不需要,但其他人可能需要。谢谢。顺便说一句,你是怎么找到这个的?
  • 翻看sdk和libraries源代码。我一般先看SO,但是如果找不到可行的解决方案,就出源代码!我最近一直在研究设计系统库,所以我最近做了很多工作以满足 UX/UI 团队的设计。
猜你喜欢
  • 2011-11-06
  • 2012-07-23
  • 2011-12-25
  • 2015-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多