Membuat Login Form Elegan dengan Jetpack Compose di Android Studio

Nama    : Iftala Zahri Sukmana
NRP      : 5025221002
Kelas     : G
Kode GitHub :  https://github.com/ifzahri/ppb/tree/main/loginform

Selamat datang di blog teknis hari ini! Dalam artikel ini, saya akan membahas cara membuat form login yang modern dan fungsional menggunakan Jetpack Compose, library UI terbaru untuk pengembangan aplikasi Android. Mari kita pelajari cara membuat form login dengan field email, password, tombol login, dan opsi "Lupa Password" yang profesional.

Pendahuluan

Jetpack Compose telah mengubah cara kita membangun antarmuka pengguna di Android. Dengan pendekatan deklaratif dan reaktif, Compose memungkinkan pengembang untuk membuat UI yang kompleks dengan kode yang lebih sedikit dan lebih mudah dipahami.

Dalam tutorial ini, kita akan fokus pada pembuatan komponen login yang sering menjadi pintu gerbang utama untuk aplikasi. Kita akan mengimplementasikan:

  • Field input untuk email dengan validasi
  • Field input untuk password dengan visualisasi khusus
  • Tombol login dengan fungsi validasi
  • Tautan "Lupa Password" yang interaktif

Prasyarat

Sebelum memulai, pastikan Anda memiliki:

  • Android Studio versi terbaru (Arctic Fox atau yang lebih baru)
  • Proyek Android dengan Jetpack Compose yang sudah dikonfigurasi
  • Pengetahuan dasar tentang Kotlin dan Jetpack Compose

Langkah 1: Membuat Composable Login Screen

Mari kita mulai dengan membuat composable utama untuk form login. Buat file Kotlin baru dengan nama LoginScreen.kt dan tambahkan kode berikut:

import androidx.compose.foundation.layout.*
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.ImeAction
import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.unit.dp

@Composable
fun LoginScreen(
    onLoginClick: (email: String, password: String) -> Unit,
    onForgotPasswordClick: () -> Unit
) {
    var email by remember { mutableStateOf("") }
    var password by remember { mutableStateOf("") }
    var isEmailError by remember { mutableStateOf(false) }
    var isPasswordError by remember { mutableStateOf(false) }
    
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Center
    ) {
        Text(
            text = "Selamat Datang Kembali",
            style = MaterialTheme.typography.headlineMedium
        )
        
        Spacer(modifier = Modifier.height(32.dp))
        
        // Field Email
        OutlinedTextField(
            value = email,
            onValueChange = { 
                email = it
                isEmailError = false
            },
            label = { Text("Email") },
            isError = isEmailError,
            modifier = Modifier.fillMaxWidth(),
            keyboardOptions = KeyboardOptions(
                keyboardType = KeyboardType.Email,
                imeAction = ImeAction.Next
            ),
            singleLine = true
        )
        
        if (isEmailError) {
            Text(
                text = "Masukkan alamat email yang valid",
                color = MaterialTheme.colorScheme.error,
                style = MaterialTheme.typography.bodySmall,
                modifier = Modifier.align(Alignment.Start)
            )
        }
        
        Spacer(modifier = Modifier.height(16.dp))
        
        // Field Password
        OutlinedTextField(
            value = password,
            onValueChange = { 
                password = it
                isPasswordError = false
            },
            label = { Text("Password") },
            isError = isPasswordError,
            visualTransformation = PasswordVisualTransformation(),
            modifier = Modifier.fillMaxWidth(),
            keyboardOptions = KeyboardOptions(
                keyboardType = KeyboardType.Password,
                imeAction = ImeAction.Done
            ),
            singleLine = true
        )
        
        if (isPasswordError) {
            Text(
                text = "Password tidak boleh kosong",
                color = MaterialTheme.colorScheme.error,
                style = MaterialTheme.typography.bodySmall,
                modifier = Modifier.align(Alignment.Start)
            )
        }
        
        Spacer(modifier = Modifier.height(8.dp))
        
        // Lupa Password
        TextButton(
            onClick = onForgotPasswordClick,
            modifier = Modifier.align(Alignment.End)
        ) {
            Text("Lupa Password?")
        }
        
        Spacer(modifier = Modifier.height(24.dp))
        
        // Tombol Login
        Button(
            onClick = {
                // Validasi sederhana
                isEmailError = !isValidEmail(email)
                isPasswordError = password.isEmpty()
                
                if (!isEmailError && !isPasswordError) {
                    onLoginClick(email, password)
                }
            },
            modifier = Modifier
                .fillMaxWidth()
                .height(50.dp)
        ) {
            Text("Masuk")
        }
    }
}

// Validasi email sederhana
private fun isValidEmail(email: String): Boolean {
    return android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches() && email.isNotEmpty()
}

Langkah 2: Mengintegrasikan dengan MainActivity

Setelah membuat composable login, kita perlu mengintegrasikan dengan MainActivity atau navigasi aplikasi kita. Berikut contoh bagaimana menggunakan LoginScreen di MainActivity:

package com.example.loginapp

import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.ui.Modifier
import com.example.loginapp.ui.theme.LoginAppTheme

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            LoginAppTheme {
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    LoginScreen(
                        onLoginClick = { email, password ->
                            // Implementasi logika login di sini
                            performLogin(email, password)
                        },
                        onForgotPasswordClick = {
                            // Implementasi alur lupa password
                            navigateToForgotPassword()
                        }
                    )
                }
            }
        }
    }
    
    private fun performLogin(email: String, password: String) {
        // Pada aplikasi nyata, Anda akan mengautentikasi dengan backend
        // Untuk demo, kita hanya menampilkan toast
        Toast.makeText(
            this,
            "Mencoba login dengan: $email",
            Toast.LENGTH_SHORT
        ).show()
        
        // Biasanya Anda akan:
        // 1. Memanggil API autentikasi
        // 2. Menangani kasus sukses/gagal
        // 3. Navigasi ke layar utama jika sukses
    }
    
    private fun navigateToForgotPassword() {
        // Implementasi navigasi ke layar lupa password
        Toast.makeText(
            this,
            "Menuju ke layar Lupa Password",
            Toast.LENGTH_SHORT
        ).show()
    }
}

Penjelasan Komponen Utama

Mari kita bahas beberapa elemen kunci dari implementasi kita:

1. State Management

var email by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") }
var isEmailError by remember { mutableStateOf(false) }
var isPasswordError by remember { mutableStateOf(false) }

Di Jetpack Compose, kita menggunakan remember dan mutableStateOf untuk mengelola state UI. Setiap perubahan pada state ini akan memicu rekomposisi UI.

2. Field Input dengan Validasi

OutlinedTextField(
    value = email,
    onValueChange = { 
        email = it
        isEmailError = false
    },
    label = { Text("Email") },
    isError = isEmailError,
    // ...
)

if (isEmailError) {
    Text(
        text = "Masukkan alamat email yang valid",
        color = MaterialTheme.colorScheme.error,
        // ...
    )
}

Kita menggunakan OutlinedTextField untuk input, dengan state isError yang menentukan apakah field dalam keadaan error. Pesan error ditampilkan hanya jika validasi gagal.

3. Visualisasi Password

visualTransformation = PasswordVisualTransformation()

Baris ini mengubah tampilan teks menjadi bintang (*) untuk menyembunyikan password, fitur keamanan standar pada form login.

4. Validasi Form

onClick = {
    // Validasi sederhana
    isEmailError = !isValidEmail(email)
    isPasswordError = password.isEmpty()
    
    if (!isEmailError && !isPasswordError) {
        onLoginClick(email, password)
    }
}

Kita melakukan validasi saat tombol login ditekan. Jika validasi berhasil, callback onLoginClick dipanggil dengan data email dan password.

5. Fungsi Validasi Email

private fun isValidEmail(email: String): Boolean {
    return android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches() && email.isNotEmpty()
}

Fungsi ini menggunakan pola regex bawaan Android untuk memverifikasi format email.

Styling dan UI/UX

Jetpack Compose menggunakan Material Design 3 secara default, yang memberikan tampilan yang modern dan konsisten. Layout kita memusatkan elemen-elemen di layar dan memberikan spacing yang tepat untuk keterbacaan.

Beberapa pertimbangan UI/UX:

  • Text field menggunakan jenis keyboard yang sesuai (email dan password)
  • Pesan error yang jelas dan informatif
  • Tombol "Lupa Password" yang mudah diakses
  • Tombol login yang lebar dan jelas
  • Validasi realtime yang memberikan feedback langsung

Implementasi Backend (Lanjutan)

Dalam aplikasi nyata, Anda perlu menghubungkan form login dengan backend Anda. Berikut contoh skeleton untuk fungsi performLogin:

private fun performLogin(email: String, password: String) {
    // Tampilkan loading indicator
    setLoading(true)
    
    viewModel.login(email, password)
        .observe(this) { result ->
            setLoading(false)
            when (result) {
                is Result.Success -> {
                    // Simpan token dan navigasi ke home screen
                    saveAuthToken(result.data.token)
                    navigateToHome()
                }
                is Result.Error -> {
                    // Tampilkan pesan error
                    showErrorMessage(result.message)
                }
            }
        }
}

Kesimpulan

Dalam tutorial ini, kita telah membuat form login yang fungsional dan estetis menggunakan Jetpack Compose. Form ini mencakup semua elemen standar: input email dan password, validasi, tombol login, dan opsi lupa password.

Jetpack Compose memungkinkan kita membuat UI yang responsif dan interaktif dengan lebih sedikit kode dibandingkan pendekatan tradisional berbasis XML. Ini juga memfasilitasi penerapan praktik-praktik terbaik dalam desain UI/UX modern.

Komentar

Postingan populer dari blog ini

Aplikasi Starbucks Clone dengan Android Studio

Tutorial Pembuatan Aplikasi Dice Roller Interaktif dengan Jetpack Compose