Android中如何多次设置EditText光标(caret)颜色?
Android API Q+ 多次修改EditText光标颜色的问题与解决方法
我们有一个简单的EditText,想要修改光标(caret)颜色。在Android API Q(29)之前,需要通过反射访问私有字段来实现;从API Q开始,则可以使用textCursorDrawable属性设置闪烁光标的Drawable。
布局代码
对应的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实现光标颜色控制
我们可以用WrapDrawable包裹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() } }
问题:多次赋值textCursorDrawable不生效
尝试两次修改光标颜色,先设为Color.RED,再设为Color.BLUE,预期光标会变成蓝色,但实际第二次赋值无效,即使置空后重新设置也无法生效:
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) { // 设置光标颜色为红色 text.textCursorDrawable = WrapDrawable(Color.RED).apply { setBounds(0, 0, 5, text.lineHeight) } // 设置光标颜色为蓝色 !!! 不生效 !!! text.textCursorDrawable = WrapDrawable(Color.BLUE).apply { setBounds(0, 0, 5, text.lineHeight) } } } }

解决方案:更新已有Drawable实例的颜色
通过更新已设置的textCursorDrawable实例的color变量,而非重新赋值新的Drawable对象,即可实现光标颜色的多次修改:
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) { // 初始设置光标颜色为红色 text.textCursorDrawable = WrapDrawable(Color.RED).apply { setBounds(0, 0, 5, text.lineHeight) } // 修改光标颜色为蓝色 text.textCursorDrawable?.let { if (it is WrapDrawable) { it.color = Color.BLUE it.setBounds(0, 0, 5, text.lineHeight) } } } } }
内容的提问来源于stack exchange,提问作者slaviboy
相关产品推荐
相关产品推荐

