處理使用者輸入內容

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

選擇 TextField 實作方式

TextField 實作分為兩個層級:

  1. TextField 為質感設計實作。建議您選擇此實作項目,因為它符合 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 TextFieldOutlineTextField,建議使用 TextField,而非 BasicTextField。不過,如果建構的設計不需要使用 Material Design 規格的裝飾,則應使用 BasicTextField

使用 Brush API 設定樣式輸入

您可以在 TextField 中使用 Brush API 使用更進階的樣式。以下章節說明如何使用筆刷為 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 的正確性。如果不是,您可以使用可組合項或狀態容器類別做為可靠資料來源。如要進一步瞭解提升狀態的位置,請參閱狀態提升說明文件。