Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change color edittext selection handles programmatically

Tags:

android

I'm trying to change the color of an edittext programmatically. It works but as you can see from the image attached, the icons for the text selection are still using the theme color accent instead of the blue I set. How can I change it? My current code is:

editText.setBackgroundTintList(new ColorStateList(new int[][]{StateSet.WILD_CARD}, new int[]{color}));
setCursorDrawableColor(editText, color);

private void setCursorDrawableColor(EditText editText, int color) {
    try {
        Field fCursorDrawableRes = TextView.class.getDeclaredField("mCursorDrawableRes");
        fCursorDrawableRes.setAccessible(true);
        int mCursorDrawableRes = fCursorDrawableRes.getInt(editText);
        Field fEditor = TextView.class.getDeclaredField("mEditor");
        fEditor.setAccessible(true);
        Object editor = fEditor.get(editText);
        Class<?> clazz = editor.getClass();
        Field fCursorDrawable = clazz.getDeclaredField("mCursorDrawable");
        fCursorDrawable.setAccessible(true);

        Drawable[] drawables = new Drawable[2];
        Resources res = editText.getContext().getResources();
        drawables[0] = res.getDrawable(mCursorDrawableRes);
        drawables[1] = res.getDrawable(mCursorDrawableRes);
        drawables[0].setColorFilter(color, PorterDuff.Mode.SRC_IN);
        drawables[1].setColorFilter(color, PorterDuff.Mode.SRC_IN);
        fCursorDrawable.set(editor, drawables);
    } catch (final Throwable ignored) {
    }
}

edit text with color accent

like image 456
greywolf82 Avatar asked Oct 19 '25 03:10

greywolf82


1 Answers

Kotlin version, works from api 14 to api 32

import android.annotation.SuppressLint
import android.content.Context
import android.content.res.ColorStateList
import android.content.res.Resources
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.InsetDrawable
import android.graphics.drawable.RotateDrawable
import android.graphics.drawable.VectorDrawable
import android.os.Build
import android.util.TypedValue
import android.widget.TextView
import androidx.annotation.ColorInt
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.DrawableCompat
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat
import java.lang.reflect.Field
import java.lang.Exception
import kotlin.math.sqrt

@SuppressLint("PrivateApi")
fun TextView.setHandlesColor(@ColorInt color: Int) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        val size = 22.spToPx(context).toInt()
        val corner = size.toFloat() / 2
        val inset = 10.spToPx(context).toInt()

        //left drawable
        val drLeft = GradientDrawable(GradientDrawable.Orientation.BOTTOM_TOP, intArrayOf(color, color))
        drLeft.setSize(size, size)
        drLeft.cornerRadii = floatArrayOf(corner, corner, 0f, 0f, corner, corner, corner, corner)
        setTextSelectHandleLeft(InsetDrawable(drLeft, inset, 0, inset, inset))

        //right drawable
        val drRight = GradientDrawable(GradientDrawable.Orientation.BOTTOM_TOP, intArrayOf(color, color))
        drRight.setSize(size, size)
        drRight.cornerRadii = floatArrayOf(0f, 0f, corner, corner, corner, corner, corner, corner)
        setTextSelectHandleRight(InsetDrawable(drRight, inset, 0, inset, inset))

        //middle drawable
        val drMiddle = GradientDrawable(GradientDrawable.Orientation.BOTTOM_TOP, intArrayOf(color, color))
        drMiddle.setSize(size, size)
        drMiddle.cornerRadii = floatArrayOf(0f, 0f, corner, corner, corner, corner, corner, corner)
        val mInset = (sqrt(2f) * corner - corner).toInt()
        val insetDrawable = InsetDrawable(drMiddle, mInset, mInset, mInset, mInset)
        val rotateDrawable = RotateDrawable()
        rotateDrawable.drawable = insetDrawable
        rotateDrawable.toDegrees = 45f
        rotateDrawable.level = 10000
        setTextSelectHandle(rotateDrawable)
        return
    }

    try {
        val editorField = TextView::class.java.getFieldByName("mEditor")
        val editor = editorField?.get(this) ?: this
        val editorClass: Class<*> = if (editorField != null) {
            runCatching { Class.forName("android.widget.Editor") }.getOrNull() ?: editorField.javaClass
        } else {
            TextView::class.java
        }
        val handles = listOf(
            "mSelectHandleLeft" to "mTextSelectHandleLeftRes",
            "mSelectHandleRight" to "mTextSelectHandleRightRes",
            "mSelectHandleCenter" to "mTextSelectHandleRes"
        )
        for (i in 0 until handles.size) {
            editorClass.getFieldByName(handles[i].first)?.let { field: Field ->
                val drawable = field.get(editor) as? Drawable
                    ?: TextView::class.java.getFieldByName(handles[i].second)?.getInt(this)
                        ?.let { ContextCompat.getDrawable(context, it) }
                if (drawable != null) field.set(editor, drawable.tinted(color))
            }
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

fun Class<*>.getFieldByName(name: String): Field? = runCatching {
    getDeclaredField(name).apply { isAccessible = true }
}.getOrNull()

fun Number.spToPx(context: Context? = null): Float =
    (context?.resources ?: Resources.getSystem()).displayMetrics
        .let { TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, this.toFloat(), it) }

fun Drawable.tinted(@ColorInt color: Int): Drawable = when {
    this is VectorDrawableCompat -> {
        this.apply { setTintList(ColorStateList.valueOf(color)) }
    }
    Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && this is VectorDrawable -> {
        this.apply { setTintList(ColorStateList.valueOf(color)) }
    }
    else -> {
        DrawableCompat.wrap(this)
            .also { DrawableCompat.setTint(it, color) }
            .let { DrawableCompat.unwrap(it) }
    }
}
like image 98
John Avatar answered Oct 20 '25 19:10

John



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!