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

时间:2014-09-23 13:11:17

标签: 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));

10 个答案:

答案 0 :(得分:75)

使用一些反射为我做了诀窍

爪哇:

// 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);

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>

以下是一种不需要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) {
  }
}

答案 1 :(得分:9)

android:textCursorDrawable="@null"

然后在申请中:

final EditText input = new EditText(nyactivity);
input.setTextColor(getResources().getColor(R.color.black));

Get from here

答案 2 :(得分: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);
    }
}

答案 3 :(得分:2)

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

答案 4 :(得分:1)

我们设法做到了:

  1. 使用EditText创建一个布局文件,并在其上设置xml光标颜色。
  2. 充气
  3. 使用EditText,就像使用以编程方式创建的
  4. 一样

答案 5 :(得分:1)

@Jared Rummler@Oleg Barinov的启发,我精心设计了同样适用于API 15的解决方案-

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

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

        if (Build.VERSION.SDK_INT == 15) {
            // Get the editor
            Class<?> drawableFieldClass = TextView.class;
            // Set the drawables
            field = drawableFieldClass.getDeclaredField("mCursorDrawable");
            field.setAccessible(true);
            field.set(editText, drawables);

        } else {
            // Get the editor
            field = TextView.class.getDeclaredField("mEditor");
            field.setAccessible(true);
            Object editor = field.get(editText);
            // Set the drawables
            field = editor.getClass().getDeclaredField("mCursorDrawable");
            field.setAccessible(true);
            field.set(editor, drawables);
        }
    } catch (Exception e) {
        Log.e(LOG_TAG, "-> ", e);
    }
}

答案 6 :(得分:0)

2019更新:工作流畅,轻松 https://material.io/develop/android/docs/getting-started/

如果您要使用材质组件,只需使用带有颜色或自定义可绘制对象的textCursorDrawable

    <com.google.android.material.textfield.TextInputLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="12dp">

        <com.google.android.material.textfield.TextInputEditText
            android:layout_width="match_parent"
            android:textCursorDrawable="@color/red"
            android:cursorVisible="true"
            android:layout_height="wrap_content" />

    </com.google.android.material.textfield.TextInputLayout>

答案 7 :(得分:0)

这是基于John's answer

的Xamarin解决方案
        public static void SetCursorDrawableColor(EditText editText, Color color)
        {
            try
            {
                if (Build.VERSION.SdkInt >= BuildVersionCodes.Q)
                {
                    var gradientDrawable = new GradientDrawable(GradientDrawable.Orientation.BottomTop, new[] { (int)color, color });
                    gradientDrawable.SetSize(SpToPx(2, editText.Context), (int)editText.TextSize);
                    editText.TextCursorDrawable = gradientDrawable;
                    return;
                }

                var fCursorDrawableRes =
                    Class.FromType(typeof(TextView)).GetDeclaredField("mCursorDrawableRes");
                fCursorDrawableRes.Accessible = true;
                int mCursorDrawableRes = fCursorDrawableRes.GetInt(editText);
                var fEditor = Class.FromType(typeof(TextView)).GetDeclaredField("mEditor");
                fEditor.Accessible = true;
                Java.Lang.Object editor = fEditor.Get(editText);
                Class clazz = editor.Class;

                if (Build.VERSION.SdkInt >= BuildVersionCodes.P)
                {
                    //TODO This solution no longer works in Android P because of reflection
                    // Get the drawable and set a color filter
                    Drawable drawable = ContextCompat.GetDrawable(editText.Context, mCursorDrawableRes);
                    drawable.SetColorFilter(color, PorterDuff.Mode.SrcIn);
                    var fCursorDrawable = clazz.GetDeclaredField("mDrawableForCursor");
                    fCursorDrawable.Accessible = true;
                    fCursorDrawable.Set(editor, drawable);
                }
                else
                {
                    Drawable[] drawables = new Drawable[2];
                    drawables[0] = ContextCompat.GetDrawable(editText.Context, mCursorDrawableRes).Mutate();
                    drawables[1] = ContextCompat.GetDrawable(editText.Context, mCursorDrawableRes).Mutate();
                    drawables[0].SetColorFilter(color, PorterDuff.Mode.SrcIn);
                    drawables[1].SetColorFilter(color, PorterDuff.Mode.SrcIn);

                    var fCursorDrawable = clazz.GetDeclaredField("mCursorDrawable");
                    fCursorDrawable.Accessible = true;
                    fCursorDrawable.Set(editor, drawables);
                }
            }
            catch (ReflectiveOperationException) { }
            catch (Exception ex)
            {
                Crashes.TrackError(ex);
            }
        }
        public static int SpToPx(float sp, Context context)
        {
            return (int)TypedValue.ApplyDimension(ComplexUnitType.Sp, sp, context.Resources.DisplayMetrics);
        }

答案 8 :(得分:0)

您应该更改“ colorAccent”,并且为了不更改整个应用程序的此参数,可以使用ThemeOverlay。您可以在this article的最后一部分“光标和选择”中了解更多详细信息

答案 9 :(得分:0)

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        if (editText.getTextCursorDrawable() instanceof InsetDrawable) {
            InsetDrawable insetDrawable = (InsetDrawable) editText.getTextCursorDrawable();
            insetDrawable.setColorFilter(Color.BLUE, PorterDuff.Mode.SRC_ATOP);
            editText.setTextCursorDrawable(insetDrawable);
        }

        if (editText.getTextSelectHandle() instanceof BitmapDrawable) {
            BitmapDrawable insetDrawable = (BitmapDrawable) editText.getTextSelectHandle();
            insetDrawable.setColorFilter(Color.BLUE, PorterDuff.Mode.SRC_ATOP);
            editText.setTextSelectHandle(insetDrawable);
        }

        if (editText.getTextSelectHandleRight() instanceof BitmapDrawable) {
            BitmapDrawable insetDrawable = (BitmapDrawable) editText.getTextSelectHandleRight();
            insetDrawable.setColorFilter(Color.BLUE, PorterDuff.Mode.SRC_ATOP);
            editText.setTextSelectHandleRight(insetDrawable);
        }

        if (editText.getTextSelectHandleLeft() instanceof BitmapDrawable) {
            BitmapDrawable insetDrawable = (BitmapDrawable) editText.getTextSelectHandleLeft();
            insetDrawable.setColorFilter(Color.BLUE, PorterDuff.Mode.SRC_ATOP);
            editText.setTextSelectHandleLeft(insetDrawable);
        }
    }

在 Q (29) 之前参见:https://stackoverflow.com/a/44352565/2255331