處理使用者輸入內容

TextField 可讓使用者輸入及修改文字。本頁面說明如何實作 TextField、設定 TextField 輸入內容,以及設定其他 TextField 選項,例如鍵盤選項和視覺轉換使用者輸入內容。

選擇 TextField 實作

TextField 實作分為兩個層級:

  1. TextField 為 Material Design 實作。建議您選擇此實作程序,因為符合Material Design 設計準則
    • 預設樣式為「填入」
    • OutlinedTextField外框樣式版本
  2. BasicTextField 可讓使用者透過硬體或軟體鍵盤編輯文字,但無法提供提示或預留位置等裝飾。

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

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

含有「

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

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

可編輯文字欄位,帶有紫色邊框和標籤。

樣式 TextField

TextFieldBasicTextField 會共用許多常見的參數以進行自訂。TextField 原始碼內提供 TextField 的完整清單。這份清單僅列舉部分有用參數的內容:

  • 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)
    )
}

多行 TextField,包含可編輯的兩行加上標籤

如果設計需要 Material TextFieldOutlinedTextField,建議使用 TextField 而非 BasicTextField。然而,如果建構的設計不需要使用材質規格的裝飾,則應使用 BasicTextField

使用 Brush API 設定輸入樣式

您可以使用 Brush APITextField 中套用更進階的樣式。以下章節將說明如何使用 Brush 將彩色漸層新增至 TextField 輸入內容。

如要進一步瞭解如何使用 Brush API 設定文字樣式,請參閱「使用 Brush API 啟用進階樣式」。

使用 TextStyle 實作彩色漸層

如要在 TextField 中輸入文字時導入彩色漸層,請將所選的筆刷設為 TextFieldTextStyle。在本範例中,我們使用內建的筆刷搭配 linearGradient,在輸入文字至 TextField 時,查看彩虹漸層效果。

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

使用 buildAnnotatedString 和 SpanStyle 搭配 linearGradient,只自訂某段文字。
圖 3. 使用 buildAnnotatedStringSpanStyle 搭配 linearGradient,只自訂某段文字。

設定鍵盤選項

TextField 可讓您設定鍵盤設定選項 (例如鍵盤配置);或是啟用自動更正功能 (如果鍵盤有支援)。如果螢幕鍵盤不符合此處提供的選項,則可能無法保證某些選項可以使用。以下是支援的鍵盤選項清單:

  • capitalization
  • autoCorrect
  • keyboardType
  • imeAction

格式化輸入內容

TextField 可讓您為輸入值設定 VisualTransformation,例如將密碼中的字符更換為 *,或是在信用卡號碼中每隔 4 位數字插入一個連字號:

@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)
    )
}

密碼文字輸入欄位,有遮罩文字

您可以在 VisualTransformationSamples 原始碼中找到更多範例。

清理輸入內容

編輯文字的常見工作是移除前置字元,或在每次變更文字時轉換輸入字串。

做為模型,您應該假設每個 onValueChange 都可進行任意和大規模編輯。舉例來說,如果使用者使用自動更正功能,並以表情符號取代字詞或其他智慧編輯功能,就可能發生這種情況。為了正確處理這種情況,請在編寫任何轉換邏輯時假設,傳遞至 onValueChange 的目前文字與將被傳遞至 onValueChange 的前一個或下一個值無關。

如要實作不允許內容開頭為零的文字欄位,可以在每次值變更時移除所有開頭的零。

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

如要在清除文字時控制游標位置,請使用 TextFieldTextFieldValue 超載做為狀態的一部分。

狀態的最佳做法

以下列出一系列最佳做法,說明如何定義及更新 TextField 狀態,以避免應用程式發生輸入問題。

  • 使用 MutableState 代表 TextField 狀態:請避免使用 StateFlow 等回應式串流來代表 TextField 狀態,因為這些結構可能會引入非同步延遲。

class SignUpViewModel : ViewModel() {

    var username by mutableStateOf("")
        private set

    /* ... */
}

  • 避免延遲更新狀態:呼叫 onValueChange 時,請立即同步更新 TextField

// 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) }
        /*...*/
    )
}

  • 定義狀態的位置:如果 TextField 狀態需要在您輸入時進行商業邏輯驗證,將狀態提升至 ViewModel 是正確的做法。如果不是,您可以使用可組合項或狀態容器類別做為可靠資料來源。如要進一步瞭解提升狀態的位置,請參閱狀態提升說明文件。