處理使用者輸入內容

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。然而,如果建構的設計不需要使用材質規格的裝飾,則應使用 BasicTextField

使用 Brush API 輸入樣式

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