Java 如何在android中以编程方式更改Edittext光标颜色?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25996032/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 01:39:11  来源:igfitidea点击:

How to Change programmatically Edittext Cursor Color in android?

javaandroid

提问by Amit Prajapati

In android we can change the cursor color via:

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

android:textCursorDrawable="@drawable/black_color_cursor".

android:textCursorDrawable="@drawable/black_color_cursor".

How can we do this dynamically?

我们如何动态地做到这一点?

In my case I have set cursor drawable to white, but i need to change black How to do ?

就我而言,我已将光标可绘制设置为白色,但我需要更改为黑色怎么办?

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

采纳答案by Jared Rummler

Using some reflection did the trick for me

使用一些反射对我有用

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

XML:

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>


Here is a method that you can use that doesn't need an XML:

这是您可以使用的不需要 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) {
  }
}

回答by Orest Savchak

android:textCursorDrawable="@null"

Then in the application:

然后在应用程序中:

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

Get from here

从这里获取

回答by Oleg Barinov

This is a rewritten version of the function from @Jared Rummlerwith a couple of improvements:

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

  • Support for Android 4.0.x
  • The special getDrawable(Context, int)function sience the getDrawable(int)is deprecated for API 22 and above.
  • 支持安卓 4.0.x
  • API 22 及更高版本不推荐使用特殊getDrawable(Context, int)函数 sience 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);
    }
}

回答by Rotem

We managed to do it by:

我们设法做到了:

  1. Creating a layout file with just an EditText and the cursor color set in xml on it.
  2. Inflating it
  3. Using the EditText as you would use a programmatically created one
  1. 创建一个布局文件,只包含一个 EditText 和在 xml 中设置的光标颜色。
  2. 给它充气
  3. 像使用以编程方式创建的那样使用 EditText

回答by Hrishikesh Kadam

Inspired from @Jared Rummlerand @Oleg BarinovI have crafted solution which works on API 15 also -

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

回答by Amit Prajapati

2019 Updated:working smooth and easy https://material.io/develop/android/docs/getting-started/

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

If you are using material component just simply use textCursorDrawablewith color or your custom drawable.

如果您正在使用材料组件,只需简单地使用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>

回答by John

Kotlin version, works from api 14 to api 29

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

回答by stepkillah

Here is the solution for Xamarin based on John'sanswer

这是基于约翰的回答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);
        }

回答by Dmitriy Lesovoy

You should change "colorAccent" and in order not to change this parameter for the whole application you can use ThemeOverlay. You can read more detailed in this article, the last section "Cursor and Selection"

您应该更改“colorAccent”,为了不更改整个应用程序的此参数,您可以使用 ThemeOverlay。您可以在这篇文章中阅读更详细的内容,最后一节“光标和选择”