如何在android中以编程方式更改Edittext Cursor Color?

Ami*_*ati 26 java android

在android中我们可以通过以下方式更改光标颜色:

android:textCursorDrawable="@drawable/black_color_cursor".

我们怎么能动态地做到这一点?

在我的情况下,我已将光标drawable设置为白色,但我需要更改黑色怎么办?

    // Set an EditText view to get user input
    final EditText input = new EditText(nyactivity);
    input.setTextColor(getResources().getColor(R.color.black));
Run Code Online (Sandbox Code Playgroud)

Jar*_*ler 81

使用一些反射对我来说是个窍门

Java的:

// https://github.com/android/platform_frameworks_base/blob/kitkat-release/core/java/android/widget/TextView.java#L562-564
Field f = TextView.class.getDeclaredField("mCursorDrawableRes");
f.setAccessible(true);
f.set(yourEditText, R.drawable.cursor);
Run Code Online (Sandbox Code Playgroud)

XML:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >

    <solid android:color="#ff000000" />

    <size android:width="1dp" />

</shape>
Run Code Online (Sandbox Code Playgroud)

这是一个不需要XML的方法:

public static void setCursorColor(EditText view, @ColorInt int color) {
  try {
    // Get the cursor resource id
    Field field = TextView.class.getDeclaredField("mCursorDrawableRes");
    field.setAccessible(true);
    int drawableResId = field.getInt(view);

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

    // Get the drawable and set a color filter
    Drawable drawable = ContextCompat.getDrawable(view.getContext(), drawableResId);
    drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);
    Drawable[] drawables = {drawable, drawable};

    // Set the drawables
    field = editor.getClass().getDeclaredField("mCursorDrawable");
    field.setAccessible(true);
    field.set(editor, drawables);
  } catch (Exception ignored) {
  }
}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢你,你是一个救星. (2认同)
  • @PavelPavlov 从 Android P 开始,反射 `mDrawableForCursor` 在黑名单中,如果您仍想更改光标颜色,请使用 xml `android:textCursorDrawable` 选项。更多信息 https://developer.android.com/distribute/best-practices/develop/restrictions-non-sdk-interfaces (2认同)

Ore*_*hak 15

android:textCursorDrawable="@null"
Run Code Online (Sandbox Code Playgroud)

然后在申请中:

final EditText input = new EditText(nyactivity);
input.setTextColor(getResources().getColor(R.color.black));
Run Code Online (Sandbox Code Playgroud)

从这里开始

  • 对不起,但是我没有任何该怎么做的XML。 (2认同)

Ole*_*nov 7

这是来自@Jared Rummler的函数的重写版本,有一些改进:

  • 支持Android 4.0.x.
  • API 22及更高版本不推荐使用特殊getDrawable(Context, int)功能getDrawable(int).
private static final Field
        sEditorField,
        sCursorDrawableField,
        sCursorDrawableResourceField;

static {
    Field editorField = null;
    Field cursorDrawableField = null;
    Field cursorDrawableResourceField = null;
    boolean exceptionThrown = false;
    try {
        cursorDrawableResourceField = TextView.class.getDeclaredField("mCursorDrawableRes");
        cursorDrawableResourceField.setAccessible(true);
        final Class<?> drawableFieldClass;
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
            drawableFieldClass = TextView.class;
        } else {
            editorField = TextView.class.getDeclaredField("mEditor");
            editorField.setAccessible(true);
            drawableFieldClass = editorField.getType();
        }
        cursorDrawableField = drawableFieldClass.getDeclaredField("mCursorDrawable");
        cursorDrawableField.setAccessible(true);
    } catch (Exception e) {
        exceptionThrown = true;
    }
    if (exceptionThrown) {
        sEditorField = null;
        sCursorDrawableField = null;
        sCursorDrawableResourceField = null;
    } else {
        sEditorField = editorField;
        sCursorDrawableField = cursorDrawableField;
        sCursorDrawableResourceField = cursorDrawableResourceField;
    }
}

public static void setCursorColor(EditText editText, int color) {
    if (sCursorDrawableField == null) {
        return;
    }
    try {
        final Drawable drawable = getDrawable(editText.getContext(), 
                sCursorDrawableResourceField.getInt(editText));
        drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN);
        sCursorDrawableField.set(Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN
                ? editText : sEditorField.get(editText), new Drawable[] {drawable, drawable});
    } catch (Exception ignored) {
    }
}

private static Drawable getDrawable(Context context, int id) {
    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
        return context.getResources().getDrawable(id);
    } else {
        return context.getDrawable(id);
    }
}
Run Code Online (Sandbox Code Playgroud)


Joh*_*ohn 6

Kotlin 版本,适用于 api 14 到 api 29

fun setCursorDrawableColor(editText: TextView, @ColorInt color: Int) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        val gradientDrawable = GradientDrawable(GradientDrawable.Orientation.BOTTOM_TOP, intArrayOf(color, color))
        gradientDrawable.setSize(2.spToPx(editText.context).toInt(), editText.textSize.toInt())
        editText.textCursorDrawable = gradientDrawable
        return
    }

    try {
        val editorField = try {
            TextView::class.java.getDeclaredField("mEditor").apply { isAccessible = true }
        } catch (t: Throwable) {
            null
        }
        val editor = editorField?.get(editText) ?: editText
        val editorClass: Class<*> = if (editorField == null) TextView::class.java else editor.javaClass

        val tintedCursorDrawable = TextView::class.java.getDeclaredField("mCursorDrawableRes")
            .apply { isAccessible = true }
            .getInt(editText)
            .let { ContextCompat.getDrawable(editText.context, it) ?: return }
            .let { tintDrawable(it, color) }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            editorClass
                .getDeclaredField("mDrawableForCursor")
                .apply { isAccessible = true }
                .run { set(editor, tintedCursorDrawable) }
        } else {
            editorClass
                .getDeclaredField("mCursorDrawable")
                .apply { isAccessible = true }
                .run { set(editor, arrayOf(tintedCursorDrawable, tintedCursorDrawable)) }
        }
    } catch (t: Throwable) {
        t.printStackTrace()
    }
}

fun Number.spToPx(context: Context? = null): Float {
    val res = context?.resources ?: android.content.res.Resources.getSystem()
    return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, this.toFloat(), res.displayMetrics)
}

fun tintDrawable(drawable: Drawable, @ColorInt color: Int): Drawable {
    (drawable as? VectorDrawableCompat)
        ?.apply { setTintList(ColorStateList.valueOf(color)) }
        ?.let { return it }

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        (drawable as? VectorDrawable)
            ?.apply { setTintList(ColorStateList.valueOf(color)) }
            ?.let { return it }
    }

    val wrappedDrawable = DrawableCompat.wrap(drawable)
    DrawableCompat.setTint(wrappedDrawable, color)
    return DrawableCompat.unwrap(wrappedDrawable)
}
Run Code Online (Sandbox Code Playgroud)

  • ...经过 8 年的 Android 开发,我花了几个小时来更改光标颜色。我只想哭。感谢您的回答! (2认同)