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:
- 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. - 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.
- Android Q (API level 29) and above: It directly sets the
- 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 remove underline while typing
- android kotlin - EditText change underline color programmatically
- android kotlin - EditText focus change listener
- android kotlin - EditText hide keyboard on lost focus
- android kotlin - RecyclerView animation
- android kotlin - RecyclerView smooth scroll
- android kotlin - Border/divider between GridView items
- android kotlin - GridView OnItemClickListener
- android kotlin - TextView get width height programmatically
- android kotlin - TextView html formatted text
- android kotlin - Canvas draw arc between two points
- android kotlin - Canvas draw path
- android kotlin - Canvas draw circle