Lab 7
Forms and data entry elements and event listeners
📘 1. Theory
1.1. Forms and data entry elements
In mobile applications, the user often needs to enter data through various interface elements. Jetpack Compose uses declarative components to build forms:
| Element | Description | Example |
|---|---|---|
| TextField | Single-line text input field | TextField(value, onValueChange = { ... }) |
| OutlinedTextField | Text box with outline (border) | OutlinedTextField(value, onValueChange = { ... }) |
| PasswordField | Password field (with text obfuscation) | OutlinedTextField(visualTransformation = PasswordVisualTransformation()) |
| Checkbox | Checkbox (yes/no) | Checkbox(checked, onCheckedChange = { ... }) |
| RadioButton | Radio button | RadioButton(selected, onClick = { ... }) |
| Switch | Switch (on/off). | Switch(checked, onCheckedChange = { ... }) |
| Button | Performs action on button press | Button(onClick = { ... }) |
1.2. State management
In Jetpack Compose, state determines what is rendered in the user interface. To change the content, remember and mutableStateOf() are used.
var username by remember { mutableStateOf("") }
The user interface is automatically updated when there is a value change.
1.3. Event Listeners
Event listeners are functions which react to user action - button click, text change, choice made, etc.
Example:
// Button click
Button(onClick = { Log.d("BTN", "Pressed button!") }) { Text("Send") }
// Text change
TextField(
value = text,
onValueChange = { newValue -> text = newValue }
)
1.4.Data validation
Before the entered data is sent, a check (validation) is often performed.:
if (username.isBlank()) {
Toast.makeText(context, "Please, enter name!", Toast.LENGTH_SHORT).show()
}
💡Examples of elements usage
TextField
@Composable
fun SimpleTextFieldExample() {
var name by remember { mutableStateOf("") }
Column(modifier = Modifier.padding(16.dp)) {
Text("Enter name:")
TextField(
value = name,
onValueChange = { name = it },
label = { Text("Name") }
)
Text("Hello, $name")
}
}
OutlinedTextField
@Composable
fun OutlinedTextFieldExample() {
var email by remember { mutableStateOf("") }
Column(modifier = Modifier.padding(16.dp)) {
Text("Enter email:")
OutlinedTextField(
value = email,
onValueChange = { email = it },
label = { Text("Email address") },
placeholder = { Text("example@mail.com") }
)
}
}
PasswordField
@Composable
fun PasswordFieldExample() {
var password by remember { mutableStateOf("") }
Column(modifier = Modifier.padding(16.dp)) {
Text("Enter password:")
OutlinedTextField(
value = password,
onValueChange = { password = it },
label = { Text("Password") },
visualTransformation = PasswordVisualTransformation()
)
}
}
Checkbox
@Composable
fun CheckboxExample() {
var isChecked by remember { mutableStateOf(false) }
Row(
modifier = Modifier.padding(16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Checkbox(
checked = isChecked,
onCheckedChange = { isChecked = it }
)
Text(if (isChecked) "Agree" else "Do not agree")
}
}
RadioButton
@Composable
fun RadioButtonExample() {
var selectedOption by remember { mutableStateOf("Мъж") }
Column(modifier = Modifier.padding(16.dp)) {
Text("Choose gender:")
Row(verticalAlignment = Alignment.CenterVertically) {
RadioButton(
selected = selectedOption == "Male",
onClick = { selectedOption = "Male" }
)
Text("Male")
}
Row(verticalAlignment = Alignment.CenterVertically) {
RadioButton(
selected = selectedOption == "Female",
onClick = { selectedOption = "Female" }
)
Text("Female")
}
Text("Избран: $selectedOption")
}
}
Switch
@Composable
fun SwitchExample() {
var notificationsEnabled by remember { mutableStateOf(true) }
Row(
modifier = Modifier.padding(16.dp),
verticalAlignment = Alignment.CenterVertically
) {
Text("Notifications:")
Spacer(modifier = Modifier.width(8.dp))
Switch(
checked = notificationsEnabled,
onCheckedChange = { notificationsEnabled = it }
)
}
}
Button
@Composable
fun ButtonExample() {
val context = LocalContext.current
Button(
onClick = {
Toast.makeText(context, "Button is pressed!", Toast.LENGTH_SHORT).show()
},
modifier = Modifier.padding(16.dp)
) {
Text("Press")
}
}
Example:
Create a mobile app login screen with two fields:
- Username
- Password and a “Login” button that displays a Toast message with the entered data.
@Composable
fun LoginScreen() {
var username by remember { mutableStateOf("") }
var password by remember { mutableStateOf("") }
val context = LocalContext.current
Column(
modifier = Modifier
.fillMaxSize()
.padding(24.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text("Login form", fontSize = 24.sp)
Spacer(modifier = Modifier.height(16.dp))
OutlinedTextField(
value = username,
onValueChange = { username = it },
label = { Text("Username") }
)
Spacer(modifier = Modifier.height(8.dp))
OutlinedTextField(
value = password,
onValueChange = { password = it },
label = { Text("Password") },
visualTransformation = PasswordVisualTransformation()
)
Spacer(modifier = Modifier.height(16.dp))
Button(onClick = {
if (username.isBlank() || password.isBlank()) {
Toast.makeText(context, "Please, fill the required fields!", Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(context, "Login: $username / $password", Toast.LENGTH_SHORT).show()
}
}) {
Text("Login")
}
}
}
Task
Create a registration form that includes the following fields:
- Name
- Password
- Confirm password
- A checkbox for agreeing to the terms of use.
Add a “Register” button that:
- Checks if all fields are filled in;
- Checks if the passwords match;
- If there is an error — displays a Toast with an error message;
- If everything is OK — displays a message “Registration successful!”.
Tips:
Use OutlinedTextField for the fields.
Use Checkbox for the consent.
Use remember { mutableStateOf(…) } to manage the values.
Add a visual structure with Column, Spacer, and Modifier.padding().