如何设置光标的颜色(插入符号)在Android中多次

llew8vvj  于 2023-09-29  发布在  Android
关注(0)|答案(2)|浏览(134)

假设我们有一个简单的EditText,我想将光标(插入符号)更改为其他颜色,在我们使用反射来访问私有字段之前,但是随着Android API Q(29)的引入,我们现在可以使用textCursorDrawable来设置 Flink 光标的可绘制对象。
下面是EditText的xml代码

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <EditText
        android:id="@+id/editText"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Test"
        android:textSize="30sp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

现在我们可以使用WrapDrawable来 Package ColorDrawable,它将被设置为EditText的textCursorDrawable值,以便我们更改光标颜色。
下面是WrapDrawable的代码:

class WrapDrawable(color: Int) : Drawable() {

    private var drawable = ColorDrawable(color)

    @ColorInt
    var color: Int = color
        set(value) {
            field = value
            drawable = ColorDrawable(value)
        }

    override fun setBounds(left: Int, top: Int, right: Int, bottom: Int) {
        super.setBounds(left, top, right, bottom)
        drawable.setBounds(left, top, right, bottom)
    }

    override fun getConstantState(): ConstantState? {
        return drawable.constantState
    }

    override fun setAlpha(alpha: Int) {
        drawable.alpha = alpha
    }

    override fun setColorFilter(colorFilter: ColorFilter?) {
        drawable.colorFilter = colorFilter
    }

    override fun getOpacity(): Int {
        return drawable.alpha
    }

    override fun draw(canvas: Canvas) {
        drawable.draw(canvas)
    }

    override fun getIntrinsicWidth(): Int {
        return drawable.bounds.width()
    }

    override fun getIntrinsicHeight(): Int {
        return drawable.bounds.height()
    }
}

在下面的代码中,我们两次改变光标的颜色,一次是Color.RED,第二次是Color.BLUE,现在我们应该有一个蓝色的光标。但问题是,一旦设置了 textCursorDrawable,即使我们尝试使其无效,也无法更改它。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val text = findViewById<EditText>(R.id.editText)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {

            // set the cursor color to RED
            text.textCursorDrawable = WrapDrawable(Color.RED).apply {
                setBounds(0, 0, 5, text.lineHeight)
            }
            
            // set the cursor color to BLUE !!! NOT WORKING !!!
            text.textCursorDrawable = WrapDrawable(Color.BLUE).apply {
                setBounds(0, 0, 5, text.lineHeight)
            }
        }
    }
}

所以我的问题是,如何多次重新分配textCursorDrawable值?

我找到了一个解决方法,即更新现有的textCursorDrawable值,并使用color变量更改ColorDrawable。

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val text = findViewById<EditText>(R.id.editText)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {

            // set the cursor color to RED
            text.textCursorDrawable = WrapDrawable(Color.RED).apply {
                setBounds(0, 0, 5, text.lineHeight)
            }

            // set the cursor color to BLUE
            text.textCursorDrawable?.let {
                if (it is WrapDrawable) {
                    it.color = Color.BLUE
                    it.setBounds(0, 0, 5, text.lineHeight)
                }
            }
        }
    }
}
ldioqlga

ldioqlga1#

setTextCursorDrawable()的文档指出:
请注意,应用于光标Drawable的任何更改都将不可见,直到光标被隐藏并再次绘制。
我已经快速浏览了 TextViewEditText 代码,还没有确定如何进行您想要的更改。我不是说这件事办不到;我就是看不出来
相反,尝试对您的 WrapDrawable 进行如下更改:

(text.textCursorDrawable as WrapDrawable).apply {
    color = Color.BLUE
    setBounds(0, 0, 5, text.lineHeight)
}

这将起作用,并将保存新 WrapDrawable 的示例化。

更新

不能证明一个否定的,但它看起来像光标drawable不能被替换一旦设置。以下是推理。
对于API 31,在 TextView 代码中只有两个地方设置了光标可绘制。mCursorDrawable的私有作用域将限制外部访问。

  • 在TextView.java:*
private Drawable mCursorDrawable;

public void setTextCursorDrawable(@Nullable Drawable textCursorDrawable) {  
    mCursorDrawable = textCursorDrawable;  
    mCursorDrawableRes = 0;  
    if (mEditor != null) {  
        mEditor.loadCursorDrawable();  
    }  
}

@Nullable public Drawable getTextCursorDrawable() {  
    if (mCursorDrawable == null && mCursorDrawableRes != 0) {  
        mCursorDrawable = mContext.getDrawable(mCursorDrawableRes);  
    }  
    return mCursorDrawable;  
}

它是绘制光标的文本编辑器类,它返回到 TextView 以获取将要使用的可绘制对象。

  • 在Editor.java:*
Drawable mDrawableForCursor = null;

private void drawCursor(Canvas canvas, int cursorOffsetVertical) {  
    final boolean translate = cursorOffsetVertical != 0;  
    if (translate) canvas.translate(0, cursorOffsetVertical);  
    if (mDrawableForCursor != null) {  
        mDrawableForCursor.draw(canvas);  
    }  
    if (translate) canvas.translate(0, -cursorOffsetVertical);  
}

void loadCursorDrawable() {  
    if (mDrawableForCursor == null) {  
        mDrawableForCursor = mTextView.getTextCursorDrawable();  
    }  
}

loadCursorDrawablemDrawableForCursor唯一被设置的地方,因此一旦定义,就不能更改。由于不能更改,因此不能将其设置为null以拾取可能在文本视图中定义的新光标可绘制对象。
因此,总的来说,游标可以在TextView中更改,但不能传播到编辑器。

anauzrmj

anauzrmj2#

您可以使用LayeredDrawable并对其内部Drawable着色:

public static void setCursorColor(@NonNull EditText editText, int color) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            Drawable drawable = editText.getTextCursorDrawable();
            if (!(editText.getTextCursorDrawable() instanceof LayerDrawable))
                drawable = ContextCompat.getDrawable(editText.getContext(), R.drawable.edit_text_cursor_layer);
            try {
                GradientDrawable colorDrawable = (GradientDrawable) ((LayerDrawable) drawable).findDrawableByLayerId(R.id.cursor);
                colorDrawable.setColor(color);
            } catch (Exception e) {
                e.printStackTrace();
            }
            editText.setTextCursorDrawable(drawable);
    }
}

edit_text_cursor.xml

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

edit_text_cursor_layer.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/edit_text_cursor" android:id="@+id/cursor"/>
</layer-list>

相关问题