Tasarımda kullanıcı deneyimini (UX) yüksek tutabilmek için kullanıcı alışkanlarını dikkate alarak proje geliştirmek önemli bir konudur.
Bu makale Android Compose tasarımında OTP (Tek Kullanımlık Şifre) input alanını nasıl oluşturabileceğimizi örnekleyerek açıklayacaktır.
OTP ve OTP Input Nedir?
OTP banka, sosyal medya vb. hesaplarınıza giriş yaparken oluşturulan tek kullanımlık şifredir. SMS yoluyla gönderilen şifreyi alıp, ilgili sistemde giriş yapacağınız alana da OTP Input denir.
Compose tasarımında BasicTextField arayüz elamanına görsel ve işlevsel özellikler ekleyerek OTP Input oluşturacağız.
OTP Input Field Oluşturma
Tek kullanımlık şifreler, sadece rakamlardan oluşur. Klavyede sadece rakamları göstererek kullanıcıya kolaylık sağlayacağız. Bunun için klayve türünü NumberPassword (KeyboardType.NumberPassword) olarak belirtmeliyiz.
İlk önce bir kotlin dosyası oluşturup, OtpTextField compose fonksiyonu içerisinde BasicTextField tanımlayarak başlıyoruz. Kodların arasına yazdığım açıklamalarla tamamını okuyarak inceleyelim.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
import androidx.compose.foundation.border import androidx.compose.foundation.layout.* import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.text.* import androidx.compose.material3.* import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.text.TextRange import androidx.compose.ui.text.input.* import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import com.smality.otptextfield_compose.ui.theme.GreyDark import com.smality.otptextfield_compose.ui.theme.GreyLight @Composable fun OtpTextField( modifier: Modifier = Modifier, otpText: String, otpCount: Int = 6, onOtpTextChange: (String, Boolean) -> Unit ) { LaunchedEffect(Unit) { if (otpText.length > otpCount) { throw IllegalArgumentException("Otp text value, otpCount: $otpCount karakterinden fazla olmamalıdır.") } } BasicTextField( modifier = modifier, value = TextFieldValue(otpText, selection = TextRange(otpText.length)), onValueChange = { //otpCount ile girilen rakam sayısını kontrol edelim. if (it.text.length <= otpCount) { onOtpTextChange.invoke(it.text, it.text.length == otpCount) } }, //Sadece rakam görünümü olan klavye türünü belirtme keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.NumberPassword), decorationBox = { //Yatay alanda kutu şeklinde input görünümlerini oluşturma Row(horizontalArrangement = Arrangement.Center) { repeat(otpCount) { index -> CharView( index = index, text = otpText ) Spacer(modifier = Modifier.width(8.dp)) } } } ) } //Rakam karakterlerinin kutudaki görünümü @Composable private fun CharView( index: Int, text: String ) { val isFocused = text.length == index val char = when { index == text.length -> "0" index > text.length -> "" else -> text[index].toString() } //Rakam yazıldığı anda rengi GreyDark, //rakam yazılmayan bir sonraki kutuda 0 değerini GreyLight renginde belirtme Text(modifier = Modifier .width(40.dp) .border( 1.dp, when { isFocused -> GreyDark else -> GreyLight }, RoundedCornerShape(8.dp) ) .padding(2.dp), text = char, style = MaterialTheme.typography.headlineLarge, color = if (isFocused) { GreyLight } else { GreyDark }, textAlign = TextAlign.Center ) } |
Hazırladığımız OtpTextField fonksiyonunu MainActivity sınıfımızda kullanalım.:)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
import android.os.Bundle import androidx.activity.ComponentActivity import androidx.activity.compose.setContent import androidx.compose.foundation.layout.* import androidx.compose.material3.Surface import androidx.compose.runtime.* import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.smality.otptextfield_compose.ui.theme.OTPTextFieldComposeTheme class MainActivity : ComponentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContent { OTPTextFieldComposeTheme { Surface( modifier = Modifier .fillMaxSize().padding(20.dp) ) { var otpValue by remember { mutableStateOf("") } OtpTextField( otpText = otpValue, onOtpTextChange = { value, otpInputFilled -> otpValue = value } ) } } } } } |