設定文字欄位

TextField 可讓使用者輸入及修改文字。您可以使用兩種文字欄位:以狀態為準的文字欄位以值為準的文字欄位。選取要顯示內容的類型:

建議使用以狀態為基礎的文字欄位,因為這種做法更完整可靠,有助於管理 TextField 的狀態。下表列出這些文字欄位類型的差異,並說明狀態型文字欄位的主要優點:

功能

以值為準的文字欄位

州別文字欄位

州別福利

狀態管理

使用 onValueChange 回呼更新文字欄位狀態。您有責任根據 onValueChange 回報的變更,更新您自己狀態中的 value

明確使用 TextFieldState 物件管理文字輸入狀態 (值、選取範圍、組合)。系統可以記住並分享這個狀態。

  • 已移除 onValueChange 回呼,因此您無法導入非同步行為。
  • 狀態會在重新組合、設定和程序終止後繼續保留。

視覺化轉換

使用 VisualTransformation 修改顯示文字的外觀。這通常會在單一步驟中處理輸入和輸出格式。

使用 InputTransformation 可在使用者輸入內容提交至狀態前進行修改,使用 OutputTransformation 則可格式化文字欄位內容,但不會變更基礎狀態資料。

  • 您不再需要使用 OutputTransformation 提供原始純文字與轉換後文字之間的位移對應。

行數限制

接受 singleLine: Boolean, maxLines: IntminLines: Int,可控制行數。

使用 lineLimits: TextFieldLineLimits 設定文字欄位可佔用的最小和最大行數。

  • 提供 TextFieldLineLimits 類型的 lineLimits 參數,設定行數限制時可避免模稜兩可。

安全文字欄位

SecureTextField 是以狀態型文字欄位為基礎建構的可組合函式,用於撰寫密碼欄位。

  • 可讓您在幕後進行安全性最佳化,並提供預先定義的 UI (含 textObfuscationMode)。

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

選擇 TextField 實作方式

TextField 實作分為兩個層級:

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

TextField(
    state = rememberTextFieldState(initialText = "Hello"),
    label = { Text("Label") }
)

含有「Hello」字詞的可編輯文字欄位。

OutlinedTextField(
    state = rememberTextFieldState(),
    label = { Text("Label") }
)

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

樣式 TextField

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

  • textStyle
  • lineLimits

TextField(
    state = rememberTextFieldState("Hello\nWorld\nInvisible"),
    lineLimits = TextFieldLineLimits.MultiLine(maxHeightInLines = 2),
    placeholder = { Text("") },
    textStyle = TextStyle(color = Color.Blue, fontWeight = FontWeight.Bold),
    label = { Text("Enter text") },
    modifier = Modifier.padding(20.dp)
)

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

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

使用 Brush API 設定輸入內容的樣式

您可以在 TextField 中使用 Brush API,進行更進階的樣式設定。下一節說明如何使用 Brush 在 TextField 輸入內容中新增彩色漸層。

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

使用 TextStyle 實作彩色漸層

如要在 TextField 中輸入文字時實作彩色漸層,請將所選筆刷設為 TextFieldTextStyle。在本範例中,我們使用內建筆刷和 linearGradient,在 TextField 中輸入文字時,檢視彩虹漸層效果。

val brush = remember {
    Brush.linearGradient(
        colors = listOf(Color.Red, Color.Yellow, Color.Green, Color.Blue, Color.Magenta)
    )
}
TextField(
    state = rememberTextFieldState(), textStyle = TextStyle(brush = brush)
)

使用 buildAnnotatedString 和 SpanStyle,以及 linearGradient,只自訂部分文字。
圖 1. TextField內容的彩虹漸層效果。

管理文字欄位狀態

TextField 會使用名為 TextFieldState 的專屬狀態容器類別,儲存內容和目前選取項目。TextFieldState 的設計宗旨是盡可能在架構中提升層級。TextFieldState 提供的主要屬性有 2 種:

  • initialTextTextField 的內容。
  • initialSelection:指出游標或選取範圍目前所在位置。

TextFieldState 與其他方法 (例如 onValueChange 回呼) 的不同之處在於,TextFieldState 會完整封裝整個輸入流程。包括使用正確的支援資料結構、內嵌篩選器和格式化工具,以及同步處理來自不同來源的所有編輯內容。

您可以使用 TextFieldState()TextField 中提升狀態。為此,我們建議使用 rememberTextFieldState() 函式。rememberTextFieldState() 會在可組合項中建立 TextFieldState 例項、確保系統會記住狀態物件,並提供內建的儲存及還原功能:

val usernameState = rememberTextFieldState()
TextField(
    state = usernameState,
    lineLimits = TextFieldLineLimits.SingleLine,
    placeholder = { Text("Enter Username") }
)

rememberTextFieldState 可以有空白參數,也可以傳遞初始值,代表初始化時的文字值。如果在後續重組中傳遞不同的值,狀態值不會更新。如要在初始化後更新狀態,請對 TextFieldState 呼叫編輯方法。

TextField(
    state = rememberTextFieldState(initialText = "Username"),
    lineLimits = TextFieldLineLimits.SingleLine,
)

TextField,文字欄位內顯示「使用者名稱」文字。
圖 2. TextField,並以「使用者名稱」做為初始文字。

使用 TextFieldBuffer 修改文字

TextFieldBuffer 可做為可編輯的文字容器,功能類似於 StringBuilder。其中包含文字內容和目前所選內容的相關資訊。

您經常會遇到 TextFieldBuffer,做為 TextFieldState.editInputTransformation.transformInputOutputTransformation.transformOutput 等函式的接收器範圍。在這些函式中,您可以視需要讀取或更新 TextFieldBuffer。之後,這些變更會提交至 TextFieldState,或在 OutputTransformation 的情況下傳遞至算繪管道。

你可以使用 appendinsertreplacedelete 等標準編輯函式修改緩衝區內容。如要變更選取狀態,請直接設定 selection: TextRange 變數,或使用 placeCursorAtEndselectAll 等公用程式函式。選取範圍本身以 TextRange 表示,其中包含開始索引,但不包含結束索引。如果 TextRange 的開始和結束值相同 (例如 (3, 3)),表示游標位置目前未選取任何字元。

val phoneNumberState = rememberTextFieldState()

LaunchedEffect(phoneNumberState) {
    phoneNumberState.edit { // TextFieldBuffer scope
        append("123456789")
    }
}

TextField(
    state = phoneNumberState,
    inputTransformation = InputTransformation { // TextFieldBuffer scope
        if (asCharSequence().isDigitsOnly()) {
            revertAllChanges()
        }
    },
    outputTransformation = OutputTransformation {
        if (length > 0) insert(0, "(")
        if (length > 4) insert(4, ")")
        if (length > 8) insert(8, "-")
    }
)

編輯「TextFieldState」中的文字

您可以透過幾種方法,直接透過狀態變數編輯狀態:

  • edit:可讓您編輯狀態內容,並提供 TextFieldBuffer 函式,方便您使用 insertreplaceappend 等方法。

    val usernameState = rememberTextFieldState("I love Android")
    // textFieldState.text : I love Android
    // textFieldState.selection: TextRange(14, 14)
    usernameState.edit { insert(14, "!") }
    // textFieldState.text : I love Android!
    // textFieldState.selection: TextRange(15, 15)
    usernameState.edit { replace(7, 14, "Compose") }
    // textFieldState.text : I love Compose!
    // textFieldState.selection: TextRange(15, 15)
    usernameState.edit { append("!!!") }
    // textFieldState.text : I love Compose!!!!
    // textFieldState.selection: TextRange(18, 18)
    usernameState.edit { selectAll() }
    // textFieldState.text : I love Compose!!!!
    // textFieldState.selection: TextRange(0, 18)

  • setTextAndPlaceCursorAtEnd:清除目前的文字、以指定文字取代,並將游標設在結尾。

    usernameState.setTextAndPlaceCursorAtEnd("I really love Android")
    // textFieldState.text : I really love Android
    // textFieldState.selection : TextRange(21, 21)

  • clearText:清除所有文字。

    usernameState.clearText()
    // textFieldState.text :
    // textFieldState.selection : TextRange(0, 0)

如要瞭解其他 TextFieldState 函式,請參閱 TextFieldState 參考資料

修改使用者輸入內容

以下各節說明如何修改使用者輸入內容。輸入內容轉換可讓您在使用者輸入內容時進行篩選,而輸出內容轉換則會在使用者輸入內容顯示在畫面上前,先將內容格式化。TextField

使用輸入轉換功能篩選使用者輸入內容

輸入轉換功能可讓您篩選使用者輸入內容。舉例來說,如果 TextField 接受美國電話號碼,您只會接受 10 位數。InputTransformation 的結果會儲存在 TextFieldState 中。

系統內建的篩選器可滿足常見的InputTransformation用途。如要限制長度,請呼叫 InputTransformation.maxLength()

TextField(
    state = rememberTextFieldState(),
    lineLimits = TextFieldLineLimits.SingleLine,
    inputTransformation = InputTransformation.maxLength(10)
)

自訂輸入轉換

InputTransformation 是單一函式介面。實作自訂 InputTransformation 時,您需要覆寫 TextFieldBuffer.transformInput

class CustomInputTransformation : InputTransformation {
    override fun TextFieldBuffer.transformInput() {
    }
}

如果是電話號碼,請新增自訂輸入轉換,只允許在 TextField 中輸入數字:

class DigitOnlyInputTransformation : InputTransformation {
    override fun TextFieldBuffer.transformInput() {
        if (!TextUtils.isDigitsOnly(asCharSequence())) {
            revertAllChanges()
        }
    }
}

鏈結輸入轉換

如要在文字輸入內容中新增多個篩選器,請使用 then 擴充功能函式,將 InputTransformation 串連在一起。系統會依序執行篩選器。按照最佳做法,請先套用最嚴格的篩選器,避免對最終會篩除的資料進行不必要的轉換。

TextField(
    state = rememberTextFieldState(),
    inputTransformation = InputTransformation.maxLength(6)
        .then(CustomInputTransformation()),
)

新增輸入轉換後,TextField 輸入最多可接受 10 位數。

在顯示輸入內容前先設定格式

OutputTransformation 可讓您先格式化使用者輸入內容,再顯示在畫面上。與 InputTransformation 不同,透過 OutputTransformation 完成的格式設定不會儲存在 TextFieldState 中。以上一個電話號碼範例為基礎,您需要在適當位置新增半形括號和破折號:

美國電話號碼,格式正確,包含括號、破折號和對應的索引。
圖 3. 格式正確的美國電話號碼和對應的索引。

這是處理以值為基礎的 VisualTransformation TextField 的更新方式,主要差異在於您不必計算其偏移對應。

OutputTransformation 是單一抽象方法介面。如要實作自訂 OutputTransformation,您需要覆寫 transformOutput 方法:

class CustomOutputTransformation : OutputTransformation {
    override fun TextFieldBuffer.transformOutput() {
    }
}

如要設定電話號碼格式,請在索引 0 處新增左括號、在索引 4 處新增右括號,並在索引 8 處新增破折號至 OutputTransformation

class PhoneNumberOutputTransformation : OutputTransformation {
    override fun TextFieldBuffer.transformOutput() {
        if (length > 0) insert(0, "(")
        if (length > 4) insert(4, ")")
        if (length > 8) insert(8, "-")
    }
}

接著,將 OutputTransformation 新增至 TextField

TextField(
    state = rememberTextFieldState(),
    outputTransformation = PhoneNumberOutputTransformation()
)

轉換如何搭配運作

下圖顯示從文字輸入到轉換再到輸出的流程:

這張圖片顯示文字輸入內容如何經過轉換,最後成為文字輸出內容。
圖 4. 圖表:顯示文字輸入內容經過轉換後,如何成為文字輸出內容。
  1. 從輸入來源接收輸入內容。
  2. 輸入內容會透過 InputTransformation 篩選,並儲存在 TextFieldState 中。
  3. 輸入內容會透過 OutputTransformation 進行格式化。
  4. 輸入內容會顯示在 TextField 中。

設定鍵盤選項

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

  • capitalization
  • autoCorrect
  • keyboardType
  • imeAction

其他資源