Error State là trạng thái của trường nhập liệu báo hiệu trực quan dữ liệu không hợp lệ. Trong Android, Error State được triển khai qua TextInputLayout.setError(), làm nổi bật đường viền màu đỏ và hiển thị văn bản lỗi bên dưới trường. Theo Material Design Guidelines, 2026, Error State nên dễ thấy nhưng không quá mạnh: viền đỏ, văn bản lỗi, biểu tượng. Sử dụng Error State đúng cách giúp tăng tỷ lệ chuyển đổi biểu mẫu lên 20-30%, vì người dùng nhanh chóng phát hiện và sửa lỗi mà không mất ngữ cảnh.
Những điểm chính
Error State là chế độ hiển thị đặc biệt của trường nhập liệu được kích hoạt khi dữ liệu nhập không vượt qua xác thực. Trực quan, Error State bao gồm ba thành phần: thay đổi màu viền hoặc nền của trường (thường thành đỏ), xuất hiện thông báo văn bản bên dưới trường mô tả lỗi và tùy chọn biểu tượng hoặc đánh dấu. Mục đích của Error State là thu hút sự chú ý của người dùng ngay lập tức đến trường có vấn đề và đề xuất cách sửa lỗi.
Trong Android, Error State được triển khai ở cấp độ TextInputLayout từ Material Design Components. TextInputLayout bao bọc EditText và quản lý các trạng thái của nó: normal, focused, error, disabled. Phương thức setError(String) chuyển trường sang trạng thái lỗi, thay đổi màu viền và hiển thị thông báo. Khi văn bản thay đổi hoặc setError(null) được gọi, trường trở lại trạng thái normal.
Theo Material Design Guidelines, Error State nên dễ thấy nhưng không chiếm ưu thế. Màu đỏ của viền nên tương phản với trạng thái bình thường nhưng không làm quá tải giao diện. Thông báo lỗi nên chứa thông tin cụ thể về vấn đề và cách giải quyết. Biểu tượng lỗi (ví dụ: vòng tròn đỏ với dấu chấm than) củng cố tín hiệu trực quan.
Phương thức setError(CharSequence errorText) chuyển TextInputLayout sang trạng thái lỗi. Tham số errorText là văn bản được hiển thị bên dưới trường. Nếu null được truyền vào, lỗi sẽ được xóa. TextInputLayout quản lý hoạt ảnh: văn bản lỗi xuất hiện với hiệu ứng mờ dần, viền chuyển sang màu đỏ. Biểu tượng lỗi (mặc định: dấu chấm than trong vòng tròn) được hiển thị ở cuối trường.
Chi tiết quan trọng: setErrorEnabled(true) phải được gọi trước setError để dành không gian cho thông báo lỗi. Nếu không, bố cục có thể “nhảy” khi lỗi xuất hiện vì không gian không được dành trước. Nên luôn bật hỗ trợ lỗi trong XML qua app:errorEnabled="true" để tránh dịch chuyển bố cục.
Phương thức setError tự động bị xóa khi văn bản trường thay đổi nếu setErrorEnabled(true) được bật. Hành vi này thuận tiện cho xác thực thời gian thực: ngay khi người dùng bắt đầu sửa lỗi, viền đỏ biến mất và trường trở lại trạng thái bình thường. Tuy nhiên, đối với các kịch bản phức tạp, tính năng tự động xóa này có thể không mong muốn — trong những trường hợp đó, hãy quản lý lỗi thủ công.
val til = findViewById<TextInputLayout>(R.id.til_email)
// Bật hỗ trợ lỗi (đặt trong XML nếu không)
til.isErrorEnabled = true
// Đặt thông báo lỗi
til.error = "Invalid email address"
// Xóa lỗi
til.error = null
// Kiểm tra xem lỗi có tồn tại không
if (til.error != null) {
// Trường đang ở trạng thái lỗi
}
Ví dụ sử dụng thuộc tính Kotlin để truy cập setError/isErrorEnabled. TextInputLayout tự động cập nhật giao diện: thay đổi boxStrokeColor, hiển thị biểu tượng lỗi, hiển thị văn bản lỗi. Nếu văn bản trong EditText thay đổi, lỗi tự động bị xóa. Để đặt lại thủ công, gán error = null.
Không phải tất cả dự án đều sử dụng Material Design Components. Để hiển thị lỗi tùy chỉnh, bạn có thể sử dụng TextView riêng bên dưới EditText trở nên hiển thị khi có lỗi. Cách tiếp cận này cho phép kiểm soát hoàn toàn kiểu dáng và vị trí thông báo. Ví dụ, bạn có thể đặt thông báo bên phải trường, sử dụng màu nền khác hoặc thêm biểu tượng bên trái văn bản.
Trong Jetpack Compose, Error State được triển khai qua tham số isError trong OutlinedTextField hoặc TextField. Khi isError = true, viền chuyển sang đỏ và bạn có thể hiển thị văn bản lỗi qua supportingText. Compose không có tính năng tự động xóa tích hợp khi thay đổi văn bản — nhà phát triển quản lý trạng thái lỗi thủ công bằng remember và mutableStateOf.
Đối với lỗi nhóm (một thông báo cho nhiều trường, ví dụ: “Điền tất cả các trường bắt buộc”), hãy sử dụng Snackbar, Dialog hoặc khối nội tuyến ở đầu biểu mẫu. Lỗi nhóm không thay thế Error State của từng trường riêng lẻ mà bổ sung cho nó. Người dùng trước tiên thấy thông báo chung, sau đó tìm các trường cụ thể có lỗi.
| Phương pháp | Ưu điểm | Nhược điểm | Khi nào sử dụng |
|---|---|---|---|
| TextInputLayout.setError | Tiêu chuẩn, hoạt ảnh, tự động xóa | Chỉ với Material Components | Tùy chọn chính cho MDC |
| TextView riêng | Kiểm soát hoàn toàn kiểu dáng | Cần quản lý hiển thị thủ công | Chủ đề tùy chỉnh, không MDC |
| Compose isError | Tích hợp trong Compose | Quản lý trạng thái thủ công | Dự án Jetpack Compose |
| Snackbar/Dialog | Thông báo nhóm | Không gắn với trường cụ thể | Bổ sung cho Error State trường |
Màu sắc của Error State trong Material Design Components được kiểm soát qua thuộc tính boxStrokeErrorColor hoặc thuộc tính colorError trong chủ đề. Mặc định, màu đỏ hệ thống được sử dụng, nhưng có thể ghi đè trong chủ đề ứng dụng hoặc trực tiếp trong TextInputLayout qua app:boxStrokeErrorColor="@color/customErrorColor". Để hỗ trợ chủ đề tối, nên sử dụng bộ chọn với các màu khác nhau cho chế độ sáng và tối.
Biểu tượng lỗi được cấu hình qua app:errorIconDrawable. Mặc định, dấu chấm than trong vòng tròn được hiển thị. Có thể thay thế bằng biểu tượng tùy chỉnh hoặc loại bỏ hoàn toàn bằng cách đặt app:errorIconDrawable="@null". Biểu tượng được hiển thị ở cuối TextInputLayout và đóng vai trò là điểm đánh dấu trực quan bổ sung. Trong Material Design 3, biểu tượng lỗi là bắt buộc cho khả năng tiếp cận.
Hoạt ảnh xuất hiện lỗi được tích hợp trong TextInputLayout: văn bản trượt lên từ dưới với sự thay đổi độ mờ dần. Đối với hoạt ảnh tùy chỉnh, hãy sử dụng Transition API hoặc MotionLayout. Ví dụ, lắc trường khi có lỗi thu hút thêm sự chú ý. Tuy nhiên, lạm dụng hoạt ảnh làm giảm trải nghiệm người dùng — sự xuất hiện mượt mà của thông báo là đủ.
Quản lý Error State được chia thành hai giai đoạn: đặt lỗi khi xác thực trường và xóa lỗi khi sửa. Trong trường hợp đơn giản nhất, xác thực được gọi trong TextWatcher.afterTextChanged: nếu giá trị không hợp lệ, setError được gọi với thông báo lỗi. Nếu hợp lệ, setError(null) được gọi. TextInputLayout tự động ẩn lỗi khi setError(null) xóa trạng thái.
Đối với xác thực biểu mẫu, lỗi được đặt ở giai đoạn gửi biểu mẫu. Duyệt qua tất cả các trường, xác thực từng trường, đặt lỗi cho các trường không hợp lệ và tập trung vào trường lỗi đầu tiên. Nút gửi bị chặn trong quá trình này. Nếu biểu mẫu lớn, nên cuộn đến trường đầu tiên có lỗi và tự động đặt tiêu điểm vào nó.
Quy tắc tập trung một lỗi: khi gửi biểu mẫu, chỉ đặt tiêu điểm vào trường đầu tiên có lỗi. Người dùng sửa từng lỗi một và sau khi sửa, trường tiếp theo có lỗi tự động nhận được tiêu điểm. Cách tiếp cận từng bước này giảm tải nhận thức. Material TextInputLayout không chặn tiêu điểm khi đặt lỗi — việc này phải được thực hiện thủ công qua requestFocus().
Lỗi đầu tiên — thiếu isErrorEnabled. Nếu setErrorEnabled không được gọi trước setError, bố cục có thể dịch chuyển khi thông báo lỗi xuất hiện. Điều này đặc biệt quan trọng nếu trường ở giữa màn hình — người dùng mất vị trí cuộn. Luôn bật setErrorEnabled(true) trong XML qua app:errorEnabled="true" hoặc theo chương trình trước khi đặt lỗi.
Lỗi thứ hai — thông báo lỗi quá dài. Văn bản dài được ngắt xuống nhiều dòng và có thể chồng lên các trường lân cận. Độ dài thông báo lỗi được khuyến nghị là 20-40 ký tự. Nếu cần thêm thông tin, hãy sử dụng helperText ở trạng thái bình thường hoặc chú giải công cụ để giải thích thêm. Sự ngắn gọn là nền tảng của Error State tốt.
Lỗi thứ ba — bỏ qua khả năng tiếp cận. Error State phải có thể truy cập được cho trình đọc màn hình. TextInputLayout tự động thông báo lỗi qua contentDescription, nhưng các triển khai tùy chỉnh phải làm điều này thủ công. Sử dụng announceForAccessibility() hoặc android:importantForAccessibility cho thông báo lỗi. Người dùng TalkBack phải nghe thấy lỗi ngay sau khi nó xuất hiện.
| Lỗi | Vấn đề | Giải pháp |
|---|---|---|
| Không có isErrorEnabled | Dịch chuyển bố cục khi lỗi | app:errorEnabled="true" trong XML |
| Thông báo dài | Chồng lên trường lân cận | 20-40 ký tự, helperText cho chi tiết |
| Không có khả năng tiếp cận | Trình đọc màn hình không nghe thấy lỗi | Quan trọng cho người dùng TalkBack |
| Tự động xóa không kiểm tra | Trường bị coi là hợp lệ sai | Quản lý đặt lại lỗi thủ công |
Câu hỏi thường gặp
Nếu sử dụng TextInputLayout, hãy gọi setError(null). Bật setErrorEnabled(true) để không gian bên dưới thông báo vẫn được dành riêng, nhưng văn bản biến mất. Khi văn bản trong EditText thay đổi, TextInputLayout tự động xóa lỗi. Để kiểm soát thủ công, sử dụng addTextChangedListener và setError(null) ở mỗi lần thay đổi.
Bởi vì không gian cho thông báo lỗi không được dành riêng. Giải pháp: bật app:errorEnabled="true" trong XML cho TextInputLayout. Điều này dành riêng không gian cho thông báo và bố cục sẽ không dịch chuyển. Khi lỗi không hoạt động, không gian vẫn trống nhưng bố cục ổn định.
Sử dụng thuộc tính app:boxStrokeErrorColor trong XML hoặc theo chương trình qua til.setBoxStrokeErrorStateList(). Màu sắc có thể được đặt bằng bộ chọn cho các trạng thái khác nhau. Bạn cũng có thể ghi đè thuộc tính hệ thống colorError trong chủ đề ứng dụng để thay đổi màu lỗi toàn cục cho tất cả các trường.
Có, sử dụng app:errorEnabled="true" và setError() — nhưng ghi đè boxStrokeErrorColor thành màu mặc định của trường. Biểu tượng và văn bản lỗi vẫn hiển thị, nhưng viền giữ nguyên màu gốc. Tuy nhiên, điều này làm giảm khả năng hiển thị lỗi, mâu thuẫn với các khuyến nghị về khả năng tiếp cận của Material Design.
Trong Compose, sử dụng isError = true trong OutlinedTextField hoặc TextField. Văn bản lỗi được truyền qua tham số supportingText. Quản lý trạng thái bằng mutableStateOf. Xóa isError thủ công khi văn bản thay đổi. Compose không có tính năng tự động xóa lỗi, không giống như TextInputLayout trong hệ thống View.
Tổng kết
Chúng tôi sẽ phát triển ứng dụng di động chìa khóa trao tay
IT Sectr tạo các ứng dụng iOS và Android cho các công ty khởi nghiệp và doanh nghiệp từ năm 2017. Chúng tôi sẽ tư vấn và đề xuất giải pháp tốt nhất cho bạn.
Đọc thêm