Định cấu hình trường văn bản

TextField cho phép người dùng nhập và sửa đổi văn bản. Có hai loại trường văn bản mà bạn có thể sử dụng: trường văn bản dựa trên trạng tháitrường văn bản dựa trên giá trị. Chọn loại nội dung bạn muốn hiển thị:

Bạn nên sử dụng các trường văn bản dựa trên trạng thái vì chúng cung cấp một phương pháp đầy đủ và đáng tin cậy hơn để quản lý trạng thái của một TextField. Bảng sau đây trình bày những điểm khác biệt giữa các loại trường văn bản này, đồng thời nêu rõ những lợi thế chính mà trường văn bản dựa trên trạng thái mang lại:

Tính năng

Trường văn bản dựa trên giá trị

Trường văn bản dựa trên trạng thái

Lợi ích theo tiểu bang

Quản lý trạng thái

Cập nhật trạng thái trường văn bản bằng lệnh gọi lại onValueChange. Bạn có trách nhiệm cập nhật value trong trạng thái của riêng bạn dựa trên những thay đổi do onValueChange báo cáo.

Sử dụng rõ ràng đối tượng TextFieldState để quản lý trạng thái nhập văn bản (giá trị, lựa chọn, thành phần). Bạn có thể lưu và chia sẻ trạng thái này.

  • Lệnh gọi lại onValueChange đã bị xoá, điều này ngăn bạn giới thiệu các hành vi không đồng bộ.
  • Trạng thái này vẫn tồn tại sau khi kết hợp lại, thay đổi cấu hình và quá trình bị buộc tắt.

Biến đổi hình ảnh

Sử dụng VisualTransformation để sửa đổi cách văn bản hiển thị xuất hiện. Thường thì thao tác này sẽ xử lý cả định dạng đầu vào và đầu ra trong một bước.

Sử dụng InputTransformation để sửa đổi thông tin đầu vào của người dùng trước khi thông tin đó được cam kết với trạng thái và OutputTransformation để định dạng nội dung trường văn bản mà không thay đổi dữ liệu trạng thái cơ bản.

  • Bạn không cần cung cấp thông tin ánh xạ độ lệch giữa văn bản thô ban đầu và văn bản đã chuyển đổi bằng OutputTransformation nữa.

Giới hạn dòng

Chấp nhận singleLine: Boolean, maxLines: IntminLines: Int để kiểm soát số lượng dòng.

Sử dụng lineLimits: TextFieldLineLimits để định cấu hình số dòng tối thiểu và tối đa mà trường văn bản có thể chiếm.

  • Loại bỏ sự mơ hồ khi định cấu hình giới hạn dòng bằng cách cung cấp một tham số lineLimits thuộc loại TextFieldLineLimits.

Trường văn bản bảo mật

Không áp dụng

SecureTextField là một thành phần kết hợp được tạo dựa trên các trường văn bản dựa trên trạng thái để viết một trường mật khẩu.

  • Cho phép bạn tối ưu hoá để bảo mật ở cấp độ hệ thống và đi kèm với giao diện người dùng được xác định trước bằng textObfuscationMode.

Trang này mô tả cách bạn có thể triển khai TextField, tạo kiểu cho dữ liệu đầu vào TextField và định cấu hình các lựa chọn TextField khác, chẳng hạn như các lựa chọn về bàn phím và chuyển đổi trực quan dữ liệu đầu vào của người dùng.

Chọn chế độ triển khai TextField

Có hai cấp độ triển khai TextField:

  1. TextField là cách triển khai Material Design. Bạn nên chọn cách triển khai này vì cách này tuân theo các nguyên tắc của Material Design:
    • Kiểu mặc định là filled
    • OutlinedTextField là phiên bản định kiểu outlined
  2. BasicTextField cho phép người dùng chỉnh sửa văn bản thông qua bàn phím phần cứng hoặc phần mềm, nhưng không cung cấp đồ trang trí như gợi ý hoặc phần giữ chỗ.

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

Một trường văn bản có thể chỉnh sửa có từ

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

Một trường văn bản có thể chỉnh sửa với đường viền và nhãn màu tím.

Kiểu TextField

TextFieldBasicTextField cùng có chung nhiều thông số phổ biến để tuỳ chỉnh. Danh sách đầy đủ cho TextField có trong mã nguồn TextField. Đây là danh sách không đầy đủ một vài thông số hữu ích:

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

Một TextField nhiều dòng, có hai dòng có thể chỉnh sửa cùng với nhãn

Bạn nên sử dụng TextField thay vì BasicTextField khi thiết kế yêu cầu một Material TextField hoặc OutlinedTextField. Tuy nhiên, bạn nên sử dụng BasicTextField khi xây dựng các thiết kế không cần trang trí từ thông số Material.

Định cấu hình giới hạn dòng

Các thành phần kết hợp TextField hỗ trợ hoạt động cuộn dọc theo một trục duy nhất. Hành vi cuộn được xác định bằng tham số lineLimits. TextField được định cấu hình để cuộn một dòng theo chiều ngang, trong khi TextField nhiều dòng sẽ cuộn theo chiều dọc.

Sử dụng TextFieldLineLimits để chọn cấu hình đường kẻ phù hợp cho TextField:

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

Một trường văn bản có một dòng văn bản

Cấu hình SingleLine có các đặc điểm sau:

  • Văn bản không bao giờ xuống dòng và không cho phép thêm dòng mới.
  • TextField luôn có chiều cao cố định.
  • Nếu văn bản tràn, văn bản sẽ cuộn theo chiều ngang.

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

Một trường văn bản nhiều dòng có văn bản

Cấu hình MultiLine có các đặc điểm sau:

  • Chấp nhận hai tham số: minHeightInLinesmaxHeightInLines.
  • Trường văn bản có chiều cao ít nhất là minHeightInLines.
  • Nếu văn bản tràn, văn bản sẽ xuống dòng.
  • Nếu văn bản cần nhiều dòng hơn, trường này sẽ tăng kích thước cho đến khi đạt chiều cao maxHeightInLines và cuộn theo chiều dọc.

Tạo kiểu cho dữ liệu đầu vào bằng Brush API

Bạn có thể sử dụng Brush API để tạo kiểu nâng cao hơn trong TextField. Phần sau đây mô tả cách bạn có thể sử dụng Brush để thêm một hiệu ứng chuyển màu vào đầu vào TextField.

Để biết thêm thông tin về cách sử dụng Brush API để tạo kiểu cho văn bản, hãy xem phần Bật tính năng tạo kiểu nâng cao bằng Brush API.

Triển khai các chuyển màu bằng TextStyle

Để triển khai một hiệu ứng chuyển màu khi bạn nhập trong TextField, hãy đặt cọ mà bạn chọn làm TextStyle cho TextField. Trong ví dụ này, chúng ta sử dụng một bút vẽ tích hợp với linearGradient để xem hiệu ứng chuyển màu cầu vồng khi nhập văn bản vào 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)
)

Sử dụng buildAnnotatedString và SpanStyle, cùng với linearGradient, để chỉ tuỳ chỉnh một đoạn văn bản.
Hình 1. Hiệu ứng chuyển màu cầu vồng cho nội dung TextField.

Quản lý trạng thái trường văn bản

TextField sử dụng một lớp chứa thông tin trạng thái chuyên dụng có tên là TextFieldState cho nội dung và lựa chọn hiện tại. TextFieldState được thiết kế để được nâng lên bất cứ nơi nào phù hợp trong cấu trúc của bạn. TextFieldState cung cấp 2 thuộc tính chính:

  • initialText: Nội dung của TextField.
  • initialSelection: Cho biết vị trí hiện tại của con trỏ hoặc vùng chọn.

Điều phân biệt TextFieldState với các phương pháp khác, chẳng hạn như lệnh gọi lại onValueChange, là TextFieldState hoàn toàn đóng gói toàn bộ quy trình nhập. Điều này bao gồm việc sử dụng các cấu trúc dữ liệu hỗ trợ chính xác, các bộ lọc và trình định dạng nội tuyến, đồng thời đồng bộ hoá tất cả các nội dung chỉnh sửa đến từ nhiều nguồn.

Bạn có thể dùng TextFieldState() để chuyển trạng thái lên trên trong TextField. Để làm việc này, bạn nên dùng hàm rememberTextFieldState(). rememberTextFieldState() tạo thực thể TextFieldState trong thành phần kết hợp của bạn, đảm bảo đối tượng trạng thái được ghi nhớ và cung cấp chức năng lưu và khôi phục tích hợp:

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

rememberTextFieldState có thể có một tham số trống hoặc có một giá trị ban đầu được truyền vào để biểu thị giá trị của văn bản khi khởi tạo. Nếu một giá trị khác được truyền trong một lần kết hợp lại tiếp theo, thì giá trị của trạng thái sẽ không được cập nhật. Để cập nhật trạng thái sau khi trạng thái này được khởi chạy, hãy gọi các phương thức chỉnh sửa trên TextFieldState.

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

Một TextField có văn bản Tên người dùng xuất hiện bên trong trường văn bản.
Hình 2. TextField có "Tên người dùng" làm văn bản ban đầu.

Sửa đổi văn bản bằng TextFieldBuffer

TextFieldBuffer đóng vai trò là một vùng chứa văn bản có thể chỉnh sửa, có chức năng tương tự như StringBuilder. Nó chứa cả nội dung văn bản và thông tin về lựa chọn hiện tại.

Bạn thường gặp TextFieldBuffer dưới dạng phạm vi nhận trên các hàm như TextFieldState.edit, InputTransformation.transformInput hoặc OutputTransformation.transformOutput. Trong các hàm này, bạn có thể đọc hoặc cập nhật TextFieldBuffer nếu cần. Sau đó, những thay đổi này sẽ được chuyển đến TextFieldState hoặc truyền xuống quy trình kết xuất trong trường hợp OutputTransformation.

Bạn có thể sử dụng các hàm chỉnh sửa tiêu chuẩn như append, insert, replace hoặc delete để sửa đổi nội dung của vùng đệm. Để thay đổi trạng thái lựa chọn, hãy đặt trực tiếp biến selection: TextRange hoặc sử dụng các hàm tiện ích như placeCursorAtEnd hoặc selectAll. Lựa chọn này được biểu thị bằng TextRange, trong đó chỉ mục bắt đầu là bao gồm và chỉ mục kết thúc là loại trừ. TextRange có giá trị bắt đầu và giá trị kết thúc giống nhau, chẳng hạn như (3, 3), biểu thị vị trí con trỏ hiện không chọn ký tự nào.

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

Chỉnh sửa văn bản trong TextFieldState

Có một số phương thức cho phép bạn chỉnh sửa trạng thái trực tiếp thông qua biến trạng thái:

  • edit: Cho phép bạn chỉnh sửa nội dung trạng thái và cung cấp cho bạn các hàm TextFieldBuffer để bạn có thể sử dụng các phương thức như insert, replace, append, v.v.

    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: Xoá văn bản hiện tại, thay thế bằng văn bản đã cho và đặt con trỏ ở cuối.

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

  • clearText: Xoá toàn bộ văn bản.

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

Đối với các hàm TextFieldState khác, hãy xem tài liệu tham khảo về TextFieldState.

Sửa đổi dữ liệu đầu vào của người dùng

Các phần sau đây mô tả cách sửa đổi dữ liệu đầu vào của người dùng. Chuyển đổi dữ liệu đầu vào cho phép bạn lọc dữ liệu đầu vào TextField trong khi người dùng đang nhập, trong khi chuyển đổi dữ liệu đầu ra định dạng dữ liệu đầu vào của người dùng trước khi dữ liệu đó xuất hiện trên màn hình.

Lọc dữ liệu đầu vào của người dùng bằng các phép biến đổi dữ liệu đầu vào

Phép biến đổi đầu vào cho phép bạn lọc đầu vào của người dùng. Ví dụ: nếu TextField của bạn nhận một số điện thoại của Hoa Kỳ, bạn chỉ muốn chấp nhận 10 chữ số. Kết quả của InputTransformation được lưu trong TextFieldState.

Có các bộ lọc tích hợp cho các trường hợp sử dụng InputTransformation phổ biến. Để giới hạn độ dài, hãy gọi InputTransformation.maxLength():

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

Quy tắc chuyển đổi dữ liệu nhập tuỳ chỉnh

InputTransformation là một giao diện hàm đơn. Khi triển khai InputTransformation tuỳ chỉnh, bạn cần ghi đè TextFieldBuffer.transformInput:

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

Đối với số điện thoại, hãy thêm một phép biến đổi đầu vào tuỳ chỉnh chỉ cho phép nhập các chữ số vào TextField:

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

Biến đổi đầu vào theo chuỗi

Để thêm nhiều bộ lọc cho dữ liệu đầu vào văn bản, hãy liên kết các InputTransformation bằng hàm mở rộng then. Các bộ lọc được thực thi tuần tự. Theo phương pháp hay nhất, hãy áp dụng các bộ lọc chọn lọc nhất trước để tránh các phép biến đổi không cần thiết trên dữ liệu cuối cùng sẽ bị lọc ra.

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

Sau khi thêm các phép biến đổi đầu vào, đầu vào TextField sẽ chấp nhận tối đa 10 chữ số.

Định dạng dữ liệu đầu vào trước khi hiển thị

OutputTransformation cho phép bạn định dạng dữ liệu đầu vào của người dùng trước khi dữ liệu đó được hiển thị trên màn hình. Không giống như InputTransformation, định dạng được thực hiện thông qua OutputTransformation sẽ không được lưu trong TextFieldState. Dựa trên ví dụ về số điện thoại trước đó, bạn cần thêm dấu ngoặc đơn và dấu gạch ngang vào những vị trí thích hợp:

Số điện thoại của Hoa Kỳ, được định dạng đúng cách bằng dấu ngoặc đơn, dấu gạch ngang và chỉ mục tương ứng.
Hình 3. Số điện thoại tại Hoa Kỳ có định dạng phù hợp và chỉ mục tương ứng.

Đây là cách mới để xử lý VisualTransformation trong TextField dựa trên giá trị, với điểm khác biệt chính là bạn không phải tính toán các ánh xạ độ lệch của chúng.

OutputTransformation là một giao diện phương thức trừu tượng đơn. Để triển khai một OutputTransformation tuỳ chỉnh, bạn cần ghi đè phương thức transformOutput:

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

Để định dạng số điện thoại, hãy thêm dấu ngoặc mở ở chỉ mục 0, dấu ngoặc đóng ở chỉ mục 4 và dấu gạch ngang ở chỉ mục 8 vào OutputTransformation:

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

Tiếp theo, hãy thêm OutputTransformation vào TextField:

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

Cách các phép biến đổi phối hợp với nhau

Sơ đồ sau đây cho thấy quy trình từ dữ liệu đầu vào văn bản đến quá trình biến đổi thành dữ liệu đầu ra:

Hình ảnh minh hoạ cách dữ liệu đầu vào văn bản trải qua các quá trình chuyển đổi trước khi trở thành dữ liệu đầu ra văn bản.
Hình 4. Sơ đồ minh hoạ cách dữ liệu đầu vào văn bản trải qua các quá trình chuyển đổi trước khi trở thành dữ liệu đầu ra văn bản.
  1. Dữ liệu đầu vào được nhận từ nguồn đầu vào.
  2. Dữ liệu đầu vào được lọc thông qua InputTransformation và được lưu trong TextFieldState.
  3. Đầu vào được truyền qua một OutputTransformation để định dạng.
  4. Nguồn đầu vào được trình bày trong TextField.

Đặt tuỳ chọn bàn phím

TextField cho phép bạn cài đặt các tuỳ chọn cấu hình bàn phím, chẳng hạn như bố cục bàn phím hoặc bật tính năng tự động sửa lỗi nếu được bàn phím hỗ trợ. Một số tuỳ chọn có thể không được đảm bảo nếu bàn phím phần mềm không tuân thủ các tuỳ chọn được cung cấp ở đây. Dưới đây là danh sách các lựa chọn bàn phím được hỗ trợ:

  • capitalization
  • autoCorrect
  • keyboardType
  • imeAction

Lớp KeyboardOptions hiện có một tham số boolean mới là showKeyboardOnFocus. Bạn dùng tham số này dành riêng cho các thành phần TextField được tích hợp với TextFieldState. Lựa chọn này chi phối hành vi của bàn phím phần mềm khi TextField lấy tiêu điểm thông qua các phương tiện khác ngoài hoạt động tương tác trực tiếp của người dùng (ví dụ: theo phương thức lập trình).

Khi KeyboardOptions.showKeyboardOnFocus được đặt thành true, bàn phím phần mềm sẽ không tự động xuất hiện nếu TextField gián tiếp lấy tiêu điểm. Trong những trường hợp như vậy, người dùng phải nhấn rõ ràng vào chính TextField để hiện bàn phím.

Xác định logic tương tác bằng bàn phím

Nút thao tác trên bàn phím phần mềm của Android cho phép các phản hồi tương tác trong ứng dụng của bạn. Để biết thêm thông tin về cách định cấu hình nút thao tác, hãy xem phần Đặt các lựa chọn cho bàn phím.

Nút hành động trên bàn phím phần mềm (biểu tượng dấu kiểm) được khoanh tròn màu đỏ.
Hình 5. Nút hành động trên bàn phím phần mềm.

Để xác định điều gì xảy ra khi người dùng nhấn vào nút thao tác này, hãy sử dụng tham số onKeyboardAction. Tham số này chấp nhận một giao diện chức năng không bắt buộc có tên là KeyboardActionHandler. Giao diện KeyboardActionHandler chứa một phương thức duy nhất là onKeyboardAction(performDefaultAction: () -> Unit). Bằng cách cung cấp một quy trình triển khai cho phương thức onKeyboardAction này, bạn có thể giới thiệu logic tuỳ chỉnh sẽ thực thi khi người dùng nhấn nút hành động trên bàn phím.

Một số loại thao tác bàn phím tiêu chuẩn có sẵn các hành vi mặc định được tích hợp. Ví dụ: theo mặc định, việc chọn ImeAction.Next hoặc ImeAction.Previous làm loại thao tác sẽ lần lượt chuyển tiêu điểm đến trường nhập tiếp theo hoặc trước đó. Tương tự, một nút thao tác được đặt thành ImeAction.Done thường sẽ đóng bàn phím phần mềm. Các chức năng mặc định này được thực thi tự động và bạn không cần cung cấp KeyboardActionHandler.

Ngoài các thao tác mặc định này, bạn cũng có thể triển khai hành vi tuỳ chỉnh. Khi bạn cung cấp KeyboardActionHandler, phương thức onKeyboardAction của phương thức này sẽ nhận được hàm performDefaultAction. Bạn có thể gọi hàm performDefaultAction() này tại bất kỳ thời điểm nào trong logic tuỳ chỉnh để kích hoạt hành vi mặc định tiêu chuẩn được liên kết với thao tác IME hiện tại.

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

Đoạn mã này minh hoạ một trường hợp sử dụng phổ biến trên màn hình đăng ký có trường tên người dùng. Đối với trường này, ImeAction.Next được chọn cho nút thao tác trên bàn phím. Lựa chọn này cho phép bạn chuyển nhanh chóng và liền mạch đến trường mật khẩu tiếp theo.

Ngoài chế độ điều hướng tiêu chuẩn này, bạn cần phải bắt đầu quy trình xác thực trong nền cho tên người dùng khi người dùng tiếp tục nhập mật khẩu. Để đảm bảo rằng hành vi chuyển đổi tiêu điểm mặc định vốn có của ImeAction.Next được giữ lại cùng với logic xác thực tuỳ chỉnh này, hàm performDefaultAction() sẽ được gọi. Việc gọi performDefaultAction() sẽ kích hoạt ngầm hệ thống quản lý tiêu điểm cơ bản để di chuyển tiêu điểm đến phần tử thích hợp tiếp theo trên giao diện người dùng, duy trì luồng điều hướng dự kiến.

Tạo trường mật khẩu an toàn

SecureTextField là một thành phần kết hợp được xây dựng dựa trên các trường văn bản dựa trên trạng thái để viết một trường mật khẩu. Bạn nên sử dụng SecureTextField để tạo các trường văn bản mật khẩu, vì theo mặc định, trường này sẽ ẩn nội dung nhập ký tự và vô hiệu hoá các thao tác cắt và sao chép.

SecureTextField có một textObfuscationMode, giúp kiểm soát cách người dùng nhìn thấy dữ liệu đầu vào của ký tự. textObfuscationMode có các lựa chọn sau:

  • Hidden: Ẩn tất cả dữ liệu đầu vào. Hành vi mặc định trên các nền tảng máy tính.

  • Visible: Hiện tất cả dữ liệu đầu vào.

  • RevealLastTyped: Ẩn tất cả dữ liệu đầu vào, ngoại trừ ký tự cuối cùng. Hành vi mặc định trên thiết bị di động.

Tài nguyên khác