Giới thiệu
Bài viết minh họa cách động态 thay đổi icon (drawable) của EditText dựa trên độ dài text nhập vào, sử dụng TextWatcher. Ví dụ: hiện icon khi nhập ≥ 3 ký tự.
Các bước thực hiện
Bước 1: Tạo project mới
Android Studio → File → New Project → Empty Activity.
Bước 2: Tạo background bo góc (res/drawable/bg_edittext_rounded.xml)
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="https://schemas.android.com/apk/res/android">
<solid android:color="#FFFFFF" />
<stroke android:width="1dp" android:color="#2F6699" />
<corners android:radius="10dp" />
</shape>
Bước 3: Chuẩn bị icon (res/drawable/ic_custom.xml hoặc ic_custom.png)
Đặt icon muốn hiển thị khi đủ điều kiện vào res/drawable/.
Bước 4: Giao diện (res/layout/activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:layout_marginTop="30dp"
android:padding="16dp">
<EditText
android:id="@+id/etInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:paddingVertical="12dp"
android:paddingHorizontal="16dp"
android:background="@drawable/bg_edittext_rounded"
android:hint="Nhập ít nhất 3 ký tự..."
android:drawableStart="@android:drawable/ic_menu_search"
android:drawablePadding="12dp" />
</LinearLayout>
Bước 5: Logic TextWatcher (MainActivity.kt)
package com.example.dynamicedittexticon
import android.graphics.drawable.Drawable
import android.os.Build
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.widget.EditText
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Load drawable một lần
val iconDrawable: Drawable = ContextCompat.getDrawable(this, R.drawable.ic_custom)!!
.apply { setBounds(0, 0, 48, 48) } // Set size 48x48 px
etInput.addTextChangedListener(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
// Không cần xử lý
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
val length = s?.length ?: 0
if (length >= 3) {
// Hiện icon custom ở bên trái (start)
etInput.setCompoundDrawablesRelativeWithIntrinsicBounds(iconDrawable, null, null, null)
} else {
// Trở về icon mặc định (search)
etInput.setCompoundDrawablesRelativeWithIntrinsicBounds(
ContextCompat.getDrawable(this@MainActivity, android.R.drawable.ic_menu_search), null, null, null)
}
}
override fun afterTextChanged(s: Editable?) {
// Không cần xử lý
}
})
}
}
Giải thích các phương thức setCompoundDrawables
setCompoundDrawables(left, top, right, bottom): Cố định Left/Right (không RTL-aware).setCompoundDrawablesRelative(start, top, end, bottom): RTL-aware (khuyên dùng). start = trái trong LTR, phải trong RTL.setCompoundDrawablesRelativeWithIntrinsicBounds(...): Tự động dùng kích thước intrinsic của drawable, không cần setBounds thủ công.
Cách dùng với TextInputLayout (Material Design)
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/tilInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Nhập text"
app:endIconMode="custom"
app:endIconDrawable="@drawable/ic_custom">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etInput"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</com.google.android.material.textfield.TextInputLayout>
// Code Kotlin
tilInput.endIconView.setOnClickListener { /* Xử lý click */ }
// Hoặc ẩn/hiện endIcon:
tilInput.isEndIconVisible = (etInput.text.length >= 3)
Lưu ý
- Drawable size nên phù hợp (24-32dp thường dùng).
- TextWatcher gọi rất nhiều lần, tránh tạo object mới trong
onTextChanged. - Dùng
setCompoundDrawablesRelativeđể hỗ trợ RTL (tiếng Ả Rập, Hebrew).
setCompoundDrawables (không phải RelativeWithIntrinsicBounds).