Android Kotlin: How to programmatically change EditText cursor color

This code snippet demonstrates how to change the cursor color of an EditText programmatically in an Android application written in Kotlin. It achieves this by providing an extension function for EditText and utilizes different approaches based on the Android API level.

The code includes three parts:

  1. MainActivity.kt: This file defines the main activity class. It retrieves references to two EditText widgets from the layout and then calls the setCursorColor extension function to set different colors (red and blue) for their cursors.
  2. setCursorColor extension function: This function is defined as an extension for the EditText class. It takes the context and a desired color as arguments. It creates a thin, colored rectangle drawable representing the new cursor. Depending on the API level, it uses one of two approaches:
    • Android Q (API level 29) and above: It directly sets the textCursorDrawable property of the EditText with the newly created drawable.
    • Android versions below Q: It uses reflection to access private fields and methods of the TextView class (EditText inherits from TextView). It retrieves the default cursor drawable resource ID, gets a reference to the editor object, sets a color filter on the drawable, and finally replaces the default cursors with the colored one.
  3. dpToPixels extension function: This is a helper function used to convert dp (density-independent pixels) values to pixels based on the device's display metrics.

This approach offers a flexible way to customize the cursor color of EditText widgets in your application while considering compatibility across different Android versions.


MainActivity.kt

package com.cfsuman.kotlintutorials

import android.app.Activity
import android.content.Context
import android.graphics.Color
import android.graphics.PorterDuff
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.os.Build
import android.os.Bundle
import android.util.TypedValue
import android.widget.EditText
import android.widget.TextView
import androidx.core.content.ContextCompat
import java.lang.reflect.Field


class MainActivity : Activity() {
    private lateinit var editText:EditText
    private lateinit var editText2:EditText

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

        // get the widgets reference from XML layout
        editText = findViewById(R.id.editText)
        editText2 = findViewById(R.id.editText2)

        // change edit text cursor color programmatically
        editText.setCursorColor(applicationContext, Color.RED)
        editText2.setCursorColor(applicationContext, Color.BLUE)
    }
}


// extension function to set/change edit text cursor color programmatically
fun EditText.setCursorColor(context: Context, color: Int){
    val editText = this

    val shapeDrawable = GradientDrawable().apply {
        shape = GradientDrawable.RECTANGLE
        setSize(2.dpToPixels(context), 0)
        setColor(color)
    }

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
        textCursorDrawable = shapeDrawable
    }else{
        try {
            // get the cursor resource id
            TextView::class.java.getDeclaredField("mCursorDrawableRes")
                .apply {
                isAccessible = true
                val drawableResId: Int = getInt(editText)

                // get the editor
                val editorField: Field = TextView::class.java
                    .getDeclaredField("mEditor")
                editorField.isAccessible = true
                val editor: Any = editorField.get(editText)

                // get the drawable and set a color filter
                val drawable: Drawable? = ContextCompat
                    .getDrawable(editText.context, drawableResId)
                drawable?.setColorFilter(color, PorterDuff.Mode.SRC_IN)

                // set the drawables
                editor.javaClass.getDeclaredField("mCursorDrawable").apply {
                    isAccessible = true
                    set(editor, arrayOf(drawable,drawable))
                }
            }
        } catch (e: Exception) {
            // log exception here
        }
    }
}


// extension function to convert dp to equivalent pixels
fun Int.dpToPixels(context: Context):Int = TypedValue.applyDimension(
    TypedValue.COMPLEX_UNIT_DIP, this.toFloat(),
    context.resources.displayMetrics
).toInt()
activity_main.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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:tools="http://schemas.android.com/tools"
    android:background="#DCDCDC"
    android:padding="32dp">

    <EditText
        android:id="@+id/editText"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginEnd="8dp"
        android:inputType="text"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.12" />

    <EditText
        android:id="@+id/editText2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="24dp"
        android:layout_marginEnd="8dp"
        android:inputType="text"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/editText" />

</androidx.constraintlayout.widget.ConstraintLayout>
android kotlin - EditText change cursor color programmatically android kotlin - EditText change cursor color programmatically 2
More android kotlin tutorials