Android'de Giriş Alanlarının Yapılandırılması: Maskeleme, Kontrol ve IME

Kerem Aydın·7 Temmuz 2026·⏱2 dk

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 actionDone konur ve form geçişi bozulur (daha iyisi actionNext ve focusSearch/requestFocus kullanmaktı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.