Konfigurowanie pól tekstowych

TextField pozwala użytkownikom wpisywać i modyfikować tekst. Dostępne są 2 typy pól tekstowych: pola tekstowe zależne od stanu i pola tekstowe zależne od wartości. Wybierz typ treści, które chcesz wyświetlać:

Zalecamy używanie pól tekstowych zależnych od stanu, ponieważ zapewniają one bardziej kompletne i niezawodne podejście do zarządzania stanem TextField. W tabeli poniżej opisano różnice między tymi typami pól tekstowych oraz podano najważniejsze zalety pól tekstowych zależnych od stanu:

Funkcja

Pola tekstowe na podstawie wartości

Pola tekstowe zależne od stanu

Korzyści zależne od stanu

Zarządzanie stanem

Aktualizuje stan pola tekstowego za pomocą wywołania zwrotnego onValueChange. Użytkownik jest odpowiedzialny za aktualizowanie pliku value w swoim stanie na podstawie zmian zgłoszonych przez plik onValueChange.

Wyraźnie używa obiektu TextFieldState do zarządzania stanem wprowadzania tekstu (wartość, wybór, kompozycja). Stan ten można zapamiętać i udostępnić.

  • Funkcja onValueChange callback została usunięta, co uniemożliwia wprowadzenie asynchronicznych zachowań.
  • Stan przetrwa ponowne skompilowanie, konfigurację i zakończenie procesu.

Przekształcenie wizualne

Używa VisualTransformation do modyfikowania wyglądu wyświetlanego tekstu. Zwykle formatowanie danych wejściowych i wyjściowych odbywa się w jednym kroku.

Używa InputTransformation do modyfikowania danych wejściowych użytkownika przed ich zapisaniem w stanie, a także OutputTransformation do formatowania zawartości pola tekstowego bez zmiany danych stanu.

  • Nie musisz już podawać mapowania przesunięcia między oryginalnym tekstem surowym a przekształconym tekstem za pomocą OutputTransformation.

Limity linii

Akceptuje singleLine: Boolean, maxLines: Int i minLines: Int do sterowania liczbą wierszy.

Używa parametru lineLimits: TextFieldLineLimits do skonfigurowania minimalnej i maksymalnej liczby wierszy, które może zajmować pole tekstowe.

  • Usuwa niejednoznaczność podczas konfigurowania limitów linii, podając parametr lineLimits typu TextFieldLineLimits.

Bezpieczne pole tekstowe

Nie dotyczy

SecureTextField to komponent utworzony na podstawie pól tekstowych zależnych od stanu, służących do wpisywania hasła.

  • Umożliwia optymalizację pod kątem bezpieczeństwa, a także korzystanie z wstępnie zdefiniowanego interfejsu textObfuscationMode.

Na tej stronie opisano, jak zaimplementować TextField, stylizować dane wejściowe TextField i konfigurować inne opcje TextField, takie jak opcje klawiatury i wizualna zmiana danych wejściowych użytkownika.

Wybierz implementację TextField

Istnieją 2 poziomy wdrażania TextField:

  1. TextField to implementacja Material Design. Zalecamy wybranie tej implementacji, ponieważ jest ona zgodna z wytycznymi dotyczącymi Material Design:
  2. BasicTextField umożliwia użytkownikom edytowanie tekstu za pomocą klawiatury sprzętowej lub programowej, ale nie zawiera żadnych elementów dekoracyjnych, takich jak podpowiedź czy placeholder.

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

pole tekstowe z możliwością edytowania zawierające słowo;

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

Pole tekstowe z możliwością edycji, z fioletowym obramowaniem i etykietą.

Styl TextField

TextFieldBasicTextField mają wiele wspólnych parametrów do dostosowywania. Pełna lista TextField jest dostępna w kodzie źródłowym TextField. Oto niepełna lista przydatnych parametrów:

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

Wielowierszowe pole tekstowe z 2 wierszami do edycji i etykietą

Jeśli Twój projekt wymaga użycia materiału TextField lub OutlinedTextField, zalecamy użycie TextField zamiast BasicTextField. Jednak BasicTextField należy używać podczas tworzenia projektów, które nie wymagają dekoracji ze specyfikacji Material.

Konfigurowanie limitów linii

Komponenty TextField obsługują przewijanie wzdłuż jednej osi. Sposób przewijania jest określany przez parametr lineLimits. TextFields skonfigurowane do przewijania pojedynczej linii poziomo, a TextFields skonfigurowane do przewijania po wielu liniach pionowo.

Aby wybrać odpowiednią konfigurację linii dla TextField, użyj TextFieldLineLimits:

TextField(
    state = rememberTextFieldState(),
    lineLimits = TextFieldLineLimits.SingleLine
)

Jednowierszowe pole tekstowe z tekstem

Konfiguracja SingleLine ma te cechy:

  • Tekst nigdy nie jest przenoszony i nie pozwala na tworzenie nowych wierszy.
  • Element TextField ma zawsze stałą wysokość.
  • Jeśli tekst jest za długi, można go przewijać w poziomie.

TextField(
    state = rememberTextFieldState("Hello\nWorld\nHello\nWorld"),
    lineLimits = TextFieldLineLimits.MultiLine(1, 4)
)

Pole tekstowe wielowierszowe z tekstem

Konfiguracja MultiLine ma te cechy:

  • Akceptuje 2 parametry: minHeightInLinesmaxHeightInLines.
  • Pole tekstowe ma co najmniej minHeightInLines pikseli wysokości.
  • Jeśli tekst się nie mieści, zostanie przeniesiony na kolejny wiersz.
  • Jeśli tekst wymaga więcej wierszy, pole powiększa się, aż osiągnie wysokość maxHeightInLines, a następnie będzie można go przewijać w pionie.

Stylizowanie za pomocą interfejsu Brush API

Aby uzyskać bardziej zaawansowane efekty stylizacji w TextField, możesz użyć interfejsu Brush API. W tej sekcji opisaliśmy, jak za pomocą pędzla dodać kolorowy gradient do wejścia TextField.

Więcej informacji o używaniu interfejsu Brush API do stylizacji tekstu znajdziesz w artykule Włączanie zaawansowanego stylizowania za pomocą interfejsu Brush API.

Implementowanie kolorowych gradientów za pomocą TextStyle

Aby zastosować kolorowy gradient podczas pisania w polu TextField, ustaw wybrany przez siebie pędzel jako TextStyle dla pola TextField. W tym przykładzie używamy wbudowanego pędzla z linearGradient, aby wyświetlić efekt gradientu tęczy podczas wpisywania tekstu w 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)
)

Użycie metody buildAnnotatedString i SpanStyle razem z linearGradient do dostosowania tylko części tekstu.
Rysunek 1. Efekt gradientu tęczy w przypadku treści TextField.

Zarządzanie stanem pola tekstowego

TextField używa dedykowanej klasy TextFieldState do przechowywania treści i bieżącego wyboru. TextFieldState jest przeznaczony do podnoszenia w dowolnym miejscu w ramach Twojej architektury. TextFieldState udostępnia 2 główne właściwości:

  • initialText: zawartość TextField.
  • initialSelection: wskazuje, gdzie znajduje się kursor lub zaznaczony obszar.

Różnica między TextFieldState a innymi metodami, takimi jak onValueChange callback, polega na tym, że TextFieldState obejmuje cały przepływ danych wejściowych. Obejmuje to używanie prawidłowych struktur danych pomocniczych, wstawianie filtrów i formaterów, a także synchronizowanie wszystkich zmian pochodzących z różnych źródeł.

Możesz użyć elementu TextFieldState(), aby podać stan w elementach TextField. W tym celu zalecamy użycie funkcji rememberTextFieldState(). rememberTextFieldState() tworzy instancję TextFieldState w komponowalnym komponencie, zapewnia pamiętanie obiektu stanu i wbudowaną funkcję zapisywania i przywracania:

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

rememberTextFieldState może mieć pusty parametr lub przekazaną wartość początkową, która reprezentuje wartość tekstu podczas inicjalizacji. Jeśli w kolejnych składaniach zostanie przekazana inna wartość, wartość stanu nie zostanie zaktualizowana. Aby zaktualizować stan po jego zainicjowaniu, wywołaj metody edycji w obiekcie TextFieldState.

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

Pole tekstowe z tekstem „Nazwa użytkownika” w polu tekstowym.
Rysunek 2. TextField z tekstem początkowym „Nazwa użytkownika”.

Modyfikowanie tekstu za pomocą TextFieldBuffer

Element TextFieldBuffer to edytowalny kontener tekstowy o funkcjonalności podobnej do elementu StringBuilder. Zawiera on zarówno treść tekstową, jak i informacje o bieżącym zaznaczeniu.

Często spotyka się TextFieldBuffer jako zakres odbiorczy w funkcjach takich jak TextFieldState.edit, InputTransformation.transformInput lub OutputTransformation.transformOutput. W tych funkcjach możesz odczytać lub zaktualizować zmienną TextFieldBuffer w razie potrzeby. Następnie te zmiany są zapisywane w TextFieldState lub przekazywane do ścieżki renderowania w przypadku OutputTransformation.

Zawartość bufora możesz modyfikować za pomocą standardowych funkcji edycji, takich jak append, insert, replace lub delete. Aby zmienić stan wyboru, ustaw bezpośrednio zmienną selection: TextRange lub użyj funkcji pomocniczych, takich jak placeCursorAtEnd lub selectAll. Samą selekcję reprezentuje elementTextRange, gdzie indeks początkowy jest traktowany włącznie, a indeks końcowy wyłącznie. TextRange z identycznymi wartościami początkową i końcową, np. (3, 3), oznacza pozycję kursora bez zaznaczonych znaków.

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, "-")
    }
)

Edytuj tekst w aplikacji TextFieldState

Istnieje kilka metod, które umożliwiają edytowanie stanu bezpośrednio za pomocą zmiennej stanu:

  • edit: umożliwia edytowanie zawartości stanu i uzyskiwanie dostępu do funkcji TextFieldBuffer, dzięki którym można używać metod takich jak insert, replace, append i innych.

    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: czyści bieżący tekst, zastępuje go podanym tekstem i ustawia kursor na końcu.

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

  • clearText: czyści cały tekst.

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

Inne funkcje TextFieldState znajdziesz w dokumentacji funkcji TextFieldState.

Modyfikowanie danych wejściowych użytkownika

W następnych sekcjach opisujemy, jak modyfikować dane wejściowe użytkownika. Przekształcenie danych wejściowych umożliwia filtrowanie danych wejściowych TextField w trakcie ich wpisywania przez użytkownika, a przekształcenie danych wyjściowych formatuje dane wejściowe przed ich wyświetleniem na ekranie.

Filtrowanie danych wejściowych użytkownika za pomocą przekształceń danych wejściowych

Przekształcenie danych wejściowych umożliwia filtrowanie danych wejściowych od użytkownika. Jeśli na przykład TextField przyjmuje amerykański numer telefonu, możesz zaakceptować tylko 10 cyfr. Wyniki InputTransformation są zapisywane w pliku TextFieldState.

Do typowych zastosowań InputTransformation dostępne są wbudowane filtry. Aby ograniczyć długość, zadzwoń pod numer InputTransformation.maxLength():

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

Niestandardowe przekształcenia danych wejściowych

InputTransformation to interfejs jednej funkcji. Podczas implementowania niestandardowego InputTransformation musisz zastąpić:TextFieldBuffer.transformInput

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

W przypadku numeru telefonu dodaj niestandardową transformację danych wejściowych, która zezwala na wpisywanie tylko cyfr w polu TextField:

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

Łańcuchowe transformacje danych wejściowych

Aby dodać do tekstu wiele filtrów, połącz InputTransformation za pomocą funkcji rozszerzenia then. Filtry są wykonywane kolejno. Zalecamy najpierw stosować najbardziej selektywne filtry, aby uniknąć niepotrzebnych przekształceń danych, które ostatecznie zostaną odfiltrowane.

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

Po dodaniu przekształceń danych wejściowych dane wejściowe TextField mogą zawierać maksymalnie 10 cyfr.

Formatowanie danych wejściowych przed ich wyświetleniem

OutputTransformation umożliwiają formatowanie danych wejściowych użytkownika przed ich renderowaniem na ekranie. W przeciwieństwie do InputTransformation formatowanie wprowadzone za pomocą funkcji OutputTransformation nie jest zapisywane w TextFieldState. W przypadku poprzedniego przykładu numeru telefonu musisz w odpowiednich miejscach dodać nawiasy i kreski:

Amerykański numer telefonu w właściwym formacie z nawiasami, myślnikami i odpowiednimi indeksami.
Rysunek 3. amerykański numer telefonu w odpowiednim formacie i z odpowiednimi indeksami;

Jest to zaktualizowany sposób obsługi VisualTransformation w elementach TextField opartych na wartościach. Główną różnicą jest to, że nie musisz obliczać ich mapowań przesunięć.

OutputTransformation to pojedynczy abstrakcyjny interfejs metody. Aby zaimplementować niestandardową funkcję OutputTransformation, musisz zastąpić metodę transformOutput:

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

Aby sformatować numer telefonu, dodaj nawias otwierający w indeksie 0, nawias zamykający w indeksie 4 i kreskę w indeksie 8 do OutputTransformation:

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

Następnie dodaj OutputTransformation do TextField:

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

Jak działają przekształcenia

Poniższy diagram przedstawia przepływ danych od tekstu wejściowego do jego przekształcenia i wyjścia:

Wizualizacja tego, jak tekst wejściowy przechodzi przez przekształcenia, zanim stanie się tekstem wyjściowym.
Rysunek 4. Diagram pokazujący, jak tekst wejściowy przechodzi przez przekształcenia, zanim stanie się tekstem wyjściowym.
  1. Dane wejściowe są otrzymywane ze źródła sygnału.
  2. Dane wejściowe są filtrowane przez funkcję InputTransformation, która jest zapisywana w stanie TextFieldState.
  3. Dane wejściowe są przekazywane przez OutputTransformation w celu sformatowania.
  4. Dane wejściowe są wyświetlane w TextField.

Ustawianie opcji klawiatury

TextField umożliwia konfigurowanie opcji klawiatury, takich jak układ klawiatury, lub włączanie autokorekty, jeśli jest obsługiwana przez klawiaturę. Niektóre opcje mogą nie być dostępne, jeśli klawiatura programowa nie jest zgodna z opcjami podanymi tutaj. Oto lista obsługiwanych opcji klawiatury:

  • capitalization
  • autoCorrect
  • keyboardType
  • imeAction

Klasa KeyboardOptions zawiera teraz nowy parametr logiczny showKeyboardOnFocus, którego używasz w przypadku komponentów TextField zintegrowanych z TextFieldState. Ta opcja określa zachowanie klawiatury oprogramowania, gdy TextField nabiera fokusa za pomocą innych metod niż bezpośrednia interakcja użytkownika (na przykład programowo).

Gdy KeyboardOptions.showKeyboardOnFocus ma wartość Prawda, klawiatura programowa nie wyświetla się automatycznie, jeśli TextField uzyska fokus pośrednio. W takich przypadkach użytkownik musi wyraźnie kliknąć przycisk TextField, aby wyświetlić klawiaturę.

Definiowanie logiki interakcji z klawiaturą

Przycisk działania na klawiaturze programowej na Androidzie umożliwia interaktywne odpowiedzi w aplikacji. Więcej informacji o konfigurowaniu przycisku czynności znajdziesz w sekcji Ustawianie opcji klawiatury.

Czerwony okrąg z ikoną przycisku akcji klawiatury ekranowej (ikona potwierdzenia).
Rysunek 5. Przycisk działania klawiatury programowej.

Aby określić, co się dzieje, gdy użytkownik kliknie ten przycisk działania, użyj parametru onKeyboardAction. Ten parametr może przyjmować opcjonalny interfejs funkcjonalny o nazwie KeyboardActionHandler. Interfejs KeyboardActionHandler zawiera jedną metodę onKeyboardAction(performDefaultAction: () -> Unit). Dzięki implementacji tej metody onKeyboardAction możesz wprowadzić logikę niestandardową, która będzie wykonywana, gdy użytkownik naciśnie przycisk akcji na klawiaturze.

Kilka standardowych typów działań klawiatury ma wbudowane domyślne zachowania. Na przykład wybranie ImeAction.Next lub ImeAction.Previous jako typu działania spowoduje przeniesienie zaznaczenia odpowiednio do następnego lub poprzedniego pola danych. Podobnie przycisk działania ustawiony na ImeAction.Done zazwyczaj zamyka klawiaturę programową. Te domyślne funkcje są wykonywane automatycznie i nie wymagają podania KeyboardActionHandler.

Oprócz tych domyślnych działań możesz też wdrożyć zachowanie niestandardowe. Gdy podasz obiekt KeyboardActionHandler, jego metoda onKeyboardAction otrzyma funkcję performDefaultAction. Funkcję performDefaultAction() możesz wywołać w dowolnym momencie w ramach logiki niestandardowej, aby wywołać standardowe domyślne działanie powiązane z bieżącą akcją IME.

TextField(
    state = textFieldViewModel.usernameState,
    keyboardOptions = KeyboardOptions(imeAction = ImeAction.Next),
    onKeyboardAction = { performDefaultAction ->
        textFieldViewModel.validateUsername()
        performDefaultAction()
    }
)

Ten fragment kodu przedstawia typowy przypadek użycia na ekranie rejestracji z polem nazwy użytkownika. W tym polu wybrana jest opcja ImeAction.Next dla przycisku działania na klawiaturze. Dzięki temu możesz szybko i płynnie przejść do kolejnego pola hasła.

Oprócz standardowej nawigacji wymagane jest zainicjowanie procesu weryfikacji nazwy użytkownika w tle, gdy użytkownik wpisze hasło. Aby zachować domyślne zachowanie przełączania fokusa charakterystyczne dla funkcji ImeAction.Next, a zarazem zachować tę niestandardową logikę walidacji, wywoływana jest funkcja performDefaultAction(). Wywołanie funkcji performDefaultAction() implikuje uruchomienie leżącego u podstaw systemu zarządzania fokusem, aby przenieść fokus na następny odpowiedni element interfejsu, zachowując oczekiwany przepływ nawigacji.

Tworzenie bezpiecznego pola hasła

SecureTextField to komponent utworzony na podstawie pól tekstowych zależnych od stanu do zapisywania pól haseł. Zalecamy używanie znaku SecureTextField do tworzenia pól tekstowych haseł, ponieważ domyślnie ukrywa on wprowadzanie znaków i wyłącza działania wycinania i kopiowania.

SecureTextField ma textObfuscationMode, który określa, jak użytkownik widzi wprowadzanie znaków. textObfuscationMode ma te opcje:

  • Hidden: ukrywa wszystkie dane wejściowe. Domyślne działanie na platformach komputerowych.

  • Visible: wyświetla wszystkie dane wejściowe.

  • RevealLastTyped: ukrywa wszystkie dane z wyjątkiem ostatniego znaku. Domyślne zachowanie na urządzeniach mobilnych.

Dodatkowe materiały