Android'de Giriş Alanlarının Yapılandırılması: Maskeleme, Kontrol ve IME
Android'de bir giriş alanının "normal bir formdaki gibi" çalışması için görevleri ayırmak yeterlidir: klavye ve IME düğmeleri XML'de tanımlanır, kısıtlamalar filtrelerle yapılır, maskeleme görüntülemeyi biçimlendirir ve doğrulama "veriler doğru mu?" sorusuna yanıt verir.
İçindekiler
Klavye: inputType ve imeOptions
android:inputType düzeni, ipuçlarını ve giriş davranışını belirlerken; android:imeOptions klavyedeki düğmeyi (Next/Done) kontrol eder.
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/etEmail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="textEmailAddress"
android:imeOptions="actionNext"/>
Formun son alanı için genellikle actionDone kullanılır ve eylem işlenir:
etPassword.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
submitForm()
true
} else false
}
Alan çok satırlıysa actionNext koymayın: yorumlar için çoğunlukla textMultiLine gerekir ve "Enter" tuşu satır başı eklemelidir.
Kısıtlamalar: Uzunluk ve izin verilen karakterler
Klavye temiz girişi garanti etmez (kullanıcı istediğini yapıştırabilir). Bu nedenle kritik alanlar filtrelerle kısıtlanır.
Uzunluk:
etCard.filters = arrayOf(InputFilter.LengthFilter(19 + 3)) // 19 rakam + boşluklar
Yalnızca gerekli karakterler (örneğin, rakamlar ve ayırıcı):
etAmount.keyListener =
DigitsKeyListener.getInstance(Locale.getDefault(), /*sign*/ false, /*decimal*/ true)
inputType="numberDecimal" harf/boşluk yapıştırmaya karşı koruma sağlamaz. Güvenilirlik için keyListener/InputFilter kombinasyonu kullanın ve göndermeden önce metni normalize edin.
TextWatcher ile giriş maskeleme (özyineleme derdi olmadan)
Maskeleme, "metnin nasıl göründüğünü" biçimlendirmektir; doğruluğu kontrol etmek değildir. Temel kalıp: özyinelemeye karşı koruma + "ham" değerden biçimlendirme.
class MaskWatcher(
private val editText: EditText,
private val rawTransform: (String) -> String = { it.filter(Char::isDigit) },
private val format: (String) -> String
) : TextWatcher {
private var selfChange = false
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) = Unit
override fun afterTextChanged(s: Editable) {
if (selfChange) return
val raw = rawTransform(s.toString())
val formatted = format(raw)
if (formatted == s.toString()) return
selfChange = true
s.replace(0, s.length, formatted)
editText.setSelection(formatted.length.coerceAtMost(s.length))
selfChange = false
}
}
Biçimlendirme örnekleri:
fun formatCard(raw: String) =
raw.take(19).chunked(4).joinToString(" ") // 1234 5678 9012 3456
fun formatMmyy(raw: String): String {
val d = raw.take(4)
return if (d.length <= 2) d else d.substring(0, 2) + "/" + d.substring(2)
}
etCard.addTextChangedListener(MaskWatcher(etCard, format = ::formatCard))
etExpiry.addTextChangedListener(MaskWatcher(etExpiry, format = ::formatMmyy))
İmlecin "zıplamaması" önemliyse, konumu "sona" değil, biçimlendirmeden önce imlecin solundaki rakam sayısına göre geri yükleyin. Bu durum özellikle telefon numaraları ve kart bilgilerinde belirgindir.
TextInputLayout ile doğrulama ve hatalar
Formlar için TextInputLayout + TextInputEditText kombinasyonu daha kullanışlıdır: kapsayıcı hata mesajı, yardımcı metin ve sayaç gösterir.
private fun validateEmail(showError: Boolean): Boolean {
val v = etEmail.text?.toString().orEmpty().trim()
val ok = v.contains("@") && v.length <= 64
tilEmail.error = if (showError && !ok) "Geçerli bir e-posta adresi girin" else null
return ok
}
etEmail.doAfterTextChanged { validateEmail(showError = false) }
btnSubmit.setOnClickListener {
val ok = validateEmail(showError = true)
if (ok) submitForm()
}
En iyi kullanıcı deneyimi, her karakterde alanı "kırmızıya boyamak" değildir: hatayı odak kaybedildikten sonra veya ilk gönderme denemesinden sonra gösterin.
Sık yapılan hatalar
- Maskeleme ve doğrulama karıştırılır: sonuçta maskeleme düzenlemeyi engeller ve "doğruluk" kontrol edilmez.
- Özyinelemeli
TextWatcher'a karşı koruma yoktur: takılmalar veya metin "titremesi" oluşur. inputType'a çöp girişlere karşı koruma olarak güvenilir — ancak yapıştırma kısıtlamaları aşar.- Ara alanlara
actionDonekonur ve form geçişi bozulur (daha iyisiactionNextvefocusSearch/requestFocuskullanmaktır). - Maskeleme yapılır ancak "ham" veri saklama/gönderme unutulur (örneğin, boşluksuz kart numarası).
SSS
Maskeleme yalnızca regex ile yapılabilir mi?
Regex kontrol için iyidir, ancak adım adım biçimlendirme için prosedürel biçimlendirici + TextWatcher daha kullanışlıdır.
Hangisini seçmeli: EditText mi yoksa TextInputEditText mi?
Formlar için — TextInputLayout içinde TextInputEditText: hataları, ipuçlarını ve sayaçları göstermek daha kolaydır.
"Gerçek" doğrulama nerede yapılmalı?
Kullanıcı arayüzünde — yumuşak (ipuçları/hatalar), göndermeden önce — sıkı: dizgiyi normalleştirin (trim, boşlukları kaldırın) ve iş kurallarını kontrol edin.