Xử lý hoạt động đầu vào của người dùng

TextField cho phép người dùng nhập và sửa đổi văn bản. Trang này mô tả cách bạn có thể triển khai TextField, tạo kiểu đầu vào TextField và định cấu hình các tuỳ chọn TextField khác, chẳng hạn như các tuỳ chọn bàn phím và chuyển đổi trực quan hoạt động đầu vào của người dùng.

Chọn cách triển khai TextField

Có hai cấp độ triển khai TextField:

  1. TextField là cách triển khai Material Design. Bạn nên chọn cách triển khai này vì cách triển khai này tuân theo các nguyên tắc của Material Design:
    • Kiểu mặc định là filled
    • OutlinedTextField là phiên bản định kiểu outline
  2. BasicTextField cho phép người dùng chỉnh sửa văn bản thông qua bàn phím phần cứng hoặc phần mềm, nhưng không cung cấp các thành phần trang trí như gợi ý hoặc phần giữ chỗ.

@Composable
fun SimpleFilledTextFieldSample() {
    var text by remember { mutableStateOf("Hello") }

    TextField(
        value = text,
        onValueChange = { text = it },
        label = { Text("Label") }
    )
}

Một trường văn bản có thể chỉnh sửa có chứa từ đó

@Composable
fun SimpleOutlinedTextFieldSample() {
    var text by remember { mutableStateOf("") }

    OutlinedTextField(
        value = text,
        onValueChange = { text = it },
        label = { Text("Label") }
    )
}

Một trường văn bản có thể chỉnh sửa với đường viền và nhãn màu tím.

Kiểu TextField

TextFieldBasicTextField cùng có chung nhiều thông số phổ biến để tuỳ chỉnh các thông số đó. Danh sách đầy đủ cho TextField có trong mã nguồn TextField. Đây là danh sách không đầy đủ một vài thông số hữu ích:

  • singleLine
  • maxLines
  • textStyle

@Composable
fun StyledTextField() {
    var value by remember { mutableStateOf("Hello\nWorld\nInvisible") }

    TextField(
        value = value,
        onValueChange = { value = it },
        label = { Text("Enter text") },
        maxLines = 2,
        textStyle = TextStyle(color = Color.Blue, fontWeight = FontWeight.Bold),
        modifier = Modifier.padding(20.dp)
    )
}

Một TextField nhiều dòng, có hai dòng có thể chỉnh sửa cùng với nhãn

Bạn nên sử dụng TextField thay vì BasicTextField khi thiết kế yêu cầu Material TextField hoặc OutlineTextField. Tuy nhiên, bạn nên sử dụng BasicTextField khi xây dựng các thiết kế không cần trang trí từ thông số kỹ thuật của Material.

Nhập kiểu bằng API Brush

Bạn có thể sử dụng Brush API để tạo kiểu nâng cao hơn trong TextField. Phần sau đây mô tả cách bạn có thể sử dụng Bút vẽ để thêm màu biến đổi màu vào đầu vào TextField.

Để biết thêm thông tin về cách sử dụng API Bút vẽ để tạo kiểu cho văn bản, hãy xem phần Bật tính năng tạo kiểu nâng cao bằng API bút vẽ.

Triển khai màu tô chuyển tiếp bằng TextStyle

Để triển khai hiệu ứng chuyển màu khi bạn nhập trong TextField, hãy đặt bút vẽ bạn chọn làm TextStyle cho TextField. Trong ví dụ này, chúng ta sử dụng bút vẽ tích hợp có linearGradient để xem hiệu ứng chuyển màu cầu vồng khi văn bản được nhập vào TextField.

var text by remember { mutableStateOf("") }
val brush = remember {
    Brush.linearGradient(
        colors = rainbowColors
    )
}
TextField(
    value = text, onValueChange = { text = it }, textStyle = TextStyle(brush = brush)
)

Sử dụng buildAnnotationdString và SpanStyle, cùng vớiLineargradientient để chỉ tuỳ chỉnh một đoạn văn bản.
Hình 3. Sử dụng buildAnnotatedStringSpanStyle cùng với linearGradient để chỉ tuỳ chỉnh một đoạn văn bản.

Đặt tuỳ chọn bàn phím

TextField cho phép bạn cài đặt các tuỳ chọn cấu hình bàn phím, chẳng hạn như bố cục bàn phím hoặc bật tính năng tự động sửa lỗi nếu được bàn phím hỗ trợ. Một số tuỳ chọn có thể không được đảm bảo nếu bàn phím phần mềm không tuân thủ các tuỳ chọn được cung cấp ở đây. Dưới đây là danh sách các tuỳ chọn bàn phím được hỗ trợ:

  • capitalization
  • autoCorrect
  • keyboardType
  • imeAction

Định dạng nội dung nhập

TextField cho phép bạn thiết lập VisualTransformation trên giá trị nhập, ví dụ như thay thế các ký tự bằng * đối với mật khẩu hoặc chèn dấu gạch ngang cứ sau 4 chữ số đối với số thẻ tín dụng:

@Composable
fun PasswordTextField() {
    var password by rememberSaveable { mutableStateOf("") }

    TextField(
        value = password,
        onValueChange = { password = it },
        label = { Text("Enter password") },
        visualTransformation = PasswordVisualTransformation(),
        keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Password)
    )
}

Một trường văn bản nhập mật khẩu, với văn bản bị che

Bạn có thể xem thêm ví dụ trong mã nguồn VisualTransformationSamples.

Xoá nội dung nhập

Một tác vụ phổ biến khi chỉnh sửa văn bản là xoá các ký tự ở đầu hoặc biến đổi chuỗi nhập vào mỗi khi có sự thay đổi.

Như một mô hình, bạn nên giả định rằng bàn phím có thể tạo ra chỉnh sửa lớn và tuỳ ý cho từng onValueChange. Điều này có thể xảy ra, ví dụ như khi người dùng sử dụng tính năng tự động sửa, thay thế một từ bằng một biểu tượng cảm xúc hoặc các tính năng chỉnh sửa thông minh khác. Để xử lý chính xác điều này, hãy viết bất kỳ logic chuyển đổi nào với giả định rằng văn bản hiện tại đã được chuyển đến onValueChange không liên quan đến các giá trị trước đó hoặc tiếp theo sẽ được chuyển tới onValueChange.

Để triển khai trường văn bản không cho phép các số 0 ở đầu, bạn có thể thực hiện bằng cách loại bỏ tất cả số 0 đứng đầu trên mọi thay đổi giá trị.

@Composable
fun NoLeadingZeroes() {
    var input by rememberSaveable { mutableStateOf("") }
    TextField(
        value = input,
        onValueChange = { newText ->
            input = newText.trimStart { it == '0' }
        }
    )
}

Để kiểm soát vị trí con trỏ khi xóa văn bản, hãy sử dụng phương thức nạp chồng TextFieldValue của TextField như là một phần của trạng thái.

Các phương pháp hay nhất về trạng thái

Sau đây là một loạt phương pháp hay nhất để xác định và cập nhật trạng thái TextField nhằm ngăn chặn các vấn đề về đầu vào trong ứng dụng.

  • Sử dụng MutableState để biểu thị trạng thái TextField: Tránh sử dụng các luồng phản ứng như StateFlow để thể hiện trạng thái TextField, vì các cấu trúc này có thể gây ra độ trễ không đồng bộ.

class SignUpViewModel : ViewModel() {

    var username by mutableStateOf("")
        private set

    /* ... */
}

  • Tránh chậm trễ khi cập nhật trạng thái: Khi bạn gọi onValueChange, hãy cập nhật TextField một cách đồng bộ và ngay lập tức:

// SignUpViewModel.kt

class SignUpViewModel(private val userRepository: UserRepository) : ViewModel() {

    var username by mutableStateOf("")
        private set

    fun updateUsername(input: String) {
        username = input
    }
}

// SignUpScreen.kt

@Composable
fun SignUpScreen(/*...*/) {

    OutlinedTextField(
        value = viewModel.username,
        onValueChange = { username -> viewModel.updateUsername(username) }
        /*...*/
    )
}

  • Nơi xác định trạng thái: Nếu trạng thái TextField yêu cầu xác thực logic nghiệp vụ khi bạn nhập, thì việc chuyển trạng thái lên ViewModel là điều chính xác. Nếu không, bạn có thể sử dụng các thành phần kết hợp hoặc lớp phần tử giữ trạng thái làm nguồn đáng tin cậy. Để tìm hiểu thêm về vị trí chuyển trạng thái lên trên, hãy xem tài liệu về chuyển trạng thái lên trên.