Khi tiêu điểm nhập di chuyển vào hoặc ra khỏi một trường văn bản có thể chỉnh sửa, Android sẽ hiển thị hoặc ẩn phương thức nhập (chẳng hạn như bàn phím ảo) khi phù hợp. Hệ thống cũng quyết định cách giao diện người dùng và trường văn bản xuất hiện phía trên phương thức nhập. Ví dụ: khi không gian theo chiều dọc trên màn hình bị hạn chế, trường văn bản có thể lấp đầy toàn bộ không gian phía trên phương thức nhập.
Đối với hầu hết ứng dụng, những hành vi mặc định này là tất cả những gì cần thiết. Tuy nhiên, trong một số trường hợp, bạn có thể muốn kiểm soát nhiều hơn đối với chế độ hiển thị của phương thức nhập và cách phương thức đó tác động đến bố cục. Bài học này giải thích cách kiểm soát và phản hồi chế độ hiển thị phương thức nhập.
Hiện bàn phím mềm khi hoạt động bắt đầu
Mặc dù Android tập trung vào trường văn bản đầu tiên trong bố cục khi hoạt động bắt đầu, nhưng sẽ không hiển thị bàn phím mềm. Hành vi này phù hợp vì việc nhập văn bản có thể không phải là tác vụ chính trong hoạt động. Tuy nhiên, nếu việc nhập văn bản thực sự là tác vụ chính, chẳng hạn như trong màn hình đăng nhập, thì bạn nên để bàn phím mềm xuất hiện theo mặc định.
Để hiển thị phương thức nhập khi hoạt động của bạn bắt đầu, hãy thêm thuộc tính android:windowSoftInputMode
vào phần tử <activity>
chứa giá trị "stateVisible"
. Ví dụ:
<application ... >
<activity
android:windowSoftInputMode="stateVisible" ... >
...
</activity>
...
</application>
Chỉ định cách giao diện người dùng phản hồi
Khi bàn phím mềm xuất hiện trên màn hình, điều này sẽ làm giảm không gian dành cho giao diện người dùng của ứng dụng. Hệ thống sẽ quyết định cách điều chỉnh phần hiển thị của giao diện người dùng nhưng có thể không chính xác. Để đảm bảo ứng dụng của bạn hoạt động tốt nhất, hãy chỉ định cách bạn muốn hệ thống hiển thị giao diện người dùng trong không gian còn lại.
Để khai báo phương thức xử lý ưu tiên trong một hoạt động, hãy sử dụng thuộc tính android:windowSoftInputMode
trong phần tử <activity>
của tệp kê khai với một trong các giá trị "adjust" (điều chỉnh).
Ví dụ: để đảm bảo rằng hệ thống đổi kích thước bố cục thành không gian còn trống – giúp bạn có thể truy cập vào tất cả nội dung bố cục, ngay cả khi nội dung bố cục yêu cầu cuộn, hãy sử dụng "adjustResize"
:
<application ... >
<activity
android:windowSoftInputMode="adjustResize" ... >
...
</activity>
...
</application>
Bạn có thể kết hợp thông số kỹ thuật điều chỉnh với thông số kỹ thuật về chế độ hiển thị bàn phím mềm ban đầu trong phần trước:
<activity
android:windowSoftInputMode="stateVisible|adjustResize" ... >
...
</activity>
Việc chỉ định "adjustResize"
là rất quan trọng nếu giao diện người dùng của bạn bao gồm các chế độ điều khiển mà người dùng có thể cần truy cập ngay sau khi hoặc trong khi thực hiện nhập văn bản. Ví dụ: nếu bạn sử dụng bố cục tương đối để đặt thanh nút ở cuối màn hình, thì việc sử dụng "adjustResize"
sẽ đổi kích thước bố cục để thanh nút xuất hiện phía trên bàn phím mềm.
Hiện bàn phím mềm theo yêu cầu
Nếu có một phương thức trong vòng đời của hoạt động mà bạn muốn đảm bảo phương thức nhập hiển thị, thì bạn có thể sử dụng InputMethodManager
để hiển thị phương thức đó.
Ví dụ: phương thức sau sẽ sử dụng View
, trong đó người dùng cần nhập nội dung nào đó, gọi requestFocus()
để lấy tiêu điểm, sau đó gọi showSoftInput()
để mở phương thức nhập:
Kotlin
fun showSoftKeyboard(view: View) { if (view.requestFocus()) { val imm = getSystemService(InputMethodManager::class.java) imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT) } }
Java
public void showSoftKeyboard(View view) { if (view.requestFocus()) { InputMethodManager imm = getSystemService(InputMethodManager.class); imm.showSoftInput(view, InputMethodManager.SHOW_IMPLICIT); } }
Hiện bàn phím mềm một cách đáng tin cậy
Có một số trường hợp, chẳng hạn như khi một hoạt động bắt đầu, trong đó việc sử dụng InputMethodManager.showSoftInput()
để hiển thị bàn phím mềm có thể khiến người dùng không nhìn thấy bàn phím phần mềm.
Chế độ hiển thị của bàn phím mềm khi sử dụng showSoftInput()
tuỳ thuộc vào các điều kiện sau:
Khung hiển thị phải được kết nối với bàn phím phần mềm. (Đổi lại, điều này sẽ yêu cầu lấy cửa sổ được lấy làm tiêu điểm và khung hiển thị trình chỉnh sửa để yêu cầu tiêu điểm của khung hiển thị bằng
View.requestFocus()
).Chế độ hiển thị cũng có thể chịu ảnh hưởng của thuộc tính
android:windowSoftInputMode
và các cờ màshowSoftInput()
sử dụng.
Trong một số trường hợp sử dụng nhất định, chẳng hạn như khi một hoạt động đang bắt đầu, một số điều kiện bắt buộc này chưa được đáp ứng. Hệ thống không coi khung hiển thị đó là kết nối với bàn phím phần mềm, bỏ qua lệnh gọi showSoftInput()
và bàn phím mềm không hiển thị với người dùng.
Để đảm bảo bàn phím phần mềm hiển thị một cách đáng tin cậy, bạn có thể sử dụng các phương án thay thế sau:
- (Nên dùng) Sử dụng
WindowInsetsControllerCompat
. Đối tượng này hiển thị bàn phím mềm trongActivity.onCreate()
như minh hoạ trong đoạn mã sau. Lệnh gọi đảm bảo sẽ được lên lịch sau khi cửa sổ được lấy tiêu điểm.
Kotlin
editText.requestFocus() WindowCompat.getInsetsController(window, editText)!!.show(WindowInsetsCompat.Type.ime())
Java
editText.requestFocus(); WindowCompat.getInsetsController(getWindow(), editText).show(WindowInsetsCompat.Type.ime());
- Đăng một tập dữ liệu có thể chạy. Điều này đảm bảo rằng ứng dụng sẽ chờ cho đến khi nhận được sự kiện lấy tiêu điểm cửa sổ từ
View.onWindowFocusChanged()
trước khi gọishowSoftInput()
.
Kotlin
class MyEditText : EditText() { ... override fun onWindowFocusChanged(hasWindowFocus: Boolean) { if (hasWindowFocus) { requestFocus() post { val imm: InputMethodManager = getSystemService(InputMethodManager::class.java) imm.showSoftInput(this, 0) } } } }
Java
public class MyEditText extends EditText { ... @Override public void onWindowFocusChanged(boolean hasWindowFocus) { if (hasWindowFocus) { requestFocus(); post(() -> { InputMethodManager imm = getSystemService(InputMethodManager.class); imm.showSoftInput(this, 0); }); } } }
Xử lý cẩn thận các cờ hiển thị trong thời gian chạy
Khi bật/tắt chế độ hiển thị bàn phím mềm trong thời gian chạy, hãy cẩn thận để không truyền một số giá trị cờ vào các phương thức này. Ví dụ: nếu ứng dụng muốn bàn phím mềm sẽ xuất hiện khi gọi View.getWindowInsetsController().show(ime())
trong Activity.onCreate()
trong quá trình bắt đầu hoạt động, thì nhà phát triển ứng dụng phải cẩn thận để không đặt cờ SOFT_INPUT_STATE_HIDDEN
hoặc SOFT_INPUT_STATE_ALWAYS_HIDDEN
trong lần chạy đầu tiên phòng trường hợp bàn phím mềm bị ẩn đột ngột.
Hệ thống thường tự động ẩn bàn phím mềm
Trong hầu hết các trường hợp, hệ thống sẽ xử lý việc ẩn bàn phím mềm. Trường hợp này có thể là bất kỳ trường hợp nào sau đây:
- Người dùng hoàn tất tác vụ trong trường văn bản.
- Người dùng nhấn phím quay lại hoặc cử chỉ vuốt khi sử dụng tính năng điều hướng quay lại.
- Người dùng chuyển đến một ứng dụng khác và ứng dụng đó đã đặt cờ
SOFT_INPUT_STATE_HIDDEN
hoặcSOFT_INPUT_STATE_ALWAYS_HIDDEN
khi khung hiển thị đó được lấy làm tâm điểm.
Ẩn bàn phím mềm theo cách thủ công dựa trên hoạt động trước đó của hệ thống
Ứng dụng phải ẩn bàn phím mềm theo cách thủ công trong một số trường hợp, chẳng hạn như khi trường văn bản bị mất tiêu điểm trong View.OnFocusChangeListener.onFocusChange
. Hãy thận trọng khi sử dụng kỹ thuật này; việc đóng bàn phím mềm sẽ đột ngột ảnh hưởng xấu đến trải nghiệm người dùng.
Nếu ứng dụng của bạn ẩn bàn phím mềm theo cách thủ công, thì bạn cần biết liệu bàn phím mềm được hiện rõ ràng hay ngầm ẩn:
Bàn phím mềm được coi là đã hiển thị rõ ràng sau khi gọi
showSoftInput()
.Ngược lại, bàn phím mềm được xem là đã ngầm hiển thị trong một trong các điều kiện sau:
- Hệ thống đã hiển thị bàn phím mềm trong khi áp dụng
android:windowSoftInputMode
. - Ứng dụng của bạn đã chuyển
SHOW_IMPLICIT
đếnshowSoftInput()
.
- Hệ thống đã hiển thị bàn phím mềm trong khi áp dụng
Thông thường, hideSoftInputFromWindow()
sẽ ẩn bàn phím mềm bất kể cách thức được yêu cầu. Tuy nhiên, với HIDE_IMPLICIT_ONLY
, bạn có thể chỉ đóng một bàn phím mềm được yêu cầu ngầm ẩn.
Hiện hộp thoại hoặc chế độ xem lớp phủ ở đầu bàn phím mềm
Trong một số trường hợp, hoạt động của trình chỉnh sửa có thể cần phải tạo một cửa sổ lớp phủ hoặc hộp thoại không thể chỉnh sửa ở đầu bàn phím mềm.
Ứng dụng của bạn có một vài tuỳ chọn được mô tả trong các phần sau.
Tóm lại, hãy đảm bảo xử lý chính xác các cờ cửa sổ của bàn phím mềm nhắm đến cửa sổ sao cho đáp ứng các kỳ vọng sau đây về thứ tự dọc (lớp z):
- Không có cờ nào (chữ thường): Đằng sau lớp bàn phím mềm và có thể nhận văn bản.
FLAG_NOT_FOCUSABLE
: Ở đầu lớp bàn phím mềm nhưng không thể nhận văn bản.FLAG_ALT_FOCUSABLE_IM
: Ở đầu lớp bàn phím mềm, bạn có thể lấy tiêu điểm nhưng không được kết nối với bàn phím mềm. Đồng thời chặn tất cả các khung hiển thị bên dưới khung hiển thị đó để không kết nối với bàn phím mềm. Điều này rất hữu ích khi hiện hộp thoại ứng dụng không sử dụng phương thức nhập văn bản phía trên lớp bàn phím mềm.FLAG_NOT_FOCUSABLE
vàFLAG_ALT_FOCUSABLE_IM
: Đằng sau lớp bàn phím mềm nhưng không thể nhận văn bản.FLAG_NOT_FOCUSABLE
vàFLAG_NOT_TOUCH_MODAL
: Ở phía trên bàn phím mềm, hãy cho phép các sự kiện chạm "di chuyển" qua cửa sổ trên bàn phím mềm.
Tạo hộp thoại
Sử dụng cờ FLAG_ALT_FOCUSABLE_IM
trong cửa sổ hộp thoại để giữ hộp thoại ở đầu bàn phím mềm và ngăn bàn phím mềm lấy tiêu điểm:
Kotlin
val content = TextView(this) content.text = "Non-editable dialog on top of soft keyboard" content.gravity = Gravity.CENTER val builder = AlertDialog.Builder(this) .setTitle("Soft keyboard layering demo") .setView(content) mDialog = builder.create() mDialog!!.window!! .addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM) mDialog!!.show()
Java
TextView content = new TextView(this); content.setText("Non-editable dialog on top of soft keyboard"); content.setGravity(Gravity.CENTER); final AlertDialog.Builder builder = new AlertDialog.Builder(this) .setTitle("Soft keyboard layering demo") .setView(content); mDialog = builder.create(); mDialog.getWindow().addFlags(FLAG_ALT_FOCUSABLE_IM); mDialog.show();
Tạo thành phần hiển thị lớp phủ
Tạo khung hiển thị lớp phủ chỉ định loại cửa sổ TYPE_APPLICATION_OVERLAY
và cờ cửa sổ FLAG_ALT_FOCUSABLE_IM
theo hoạt động được nhắm mục tiêu bằng bàn phím mềm.
Kotlin
val params = WindowManager.LayoutParams( width, /* Overlay window width */ height, /* Overlay window height */ WindowManager.LayoutParams.TYPE_APPLICATION, /* Overlay window type */ WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM /* No need to allow for text input on top of the soft keyboard */ or WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, /* Allow touch event send to soft keyboard behind the overlay */ PixelFormat.TRANSLUCENT ) params.title = "Overlay window" mOverlayView!!.layoutParams = params windowManager.addView(mOverlayView, params)
Java
WindowManager.LayoutParams params = new WindowManager.LayoutParams( width, /* Overlay window width */ height, /* Overlay window height */ TYPE_APPLICATION, /* Overlay window type */ FLAG_ALT_FOCUSABLE_IM /* No need to allow for text input on top of the soft keyboard */ | FLAG_NOT_TOUCH_MODAL, /* Allow touch event send to soft keyboard behind the overlay */ PixelFormat.TRANSLUCENT); params.setTitle("Overlay window"); mOverlayView.setLayoutParams(params); getWindowManager().addView(mOverlayView, params);
Hiện hộp thoại hoặc chế độ xem bên dưới bàn phím mềm
Ứng dụng của bạn có thể cần tạo một hộp thoại hoặc một cửa sổ có các thuộc tính sau:
- Xuất hiện bên dưới bàn phím mềm được hoạt động của trình chỉnh sửa yêu cầu để không bị ảnh hưởng bởi việc nhập văn bản.
- Nhận biết được những thay đổi đối với kích thước phần lồng ghép của bàn phím mềm sẽ thay đổi để điều chỉnh bố cục của hộp thoại hoặc cửa sổ.
Trong trường hợp này, ứng dụng của bạn có một vài lựa chọn. Các phần sau đây mô tả những tuỳ chọn này.
Tạo hộp thoại
Tạo hộp thoại bằng cách đặt cả cờ cửa sổ FLAG_NOT_FOCUSABLE
và cờ cửa sổ FLAG_ALT_FOCUSABLE_IM
:
Kotlin
val content = TextView(this) content.text = "Non-editable dialog behind soft keyboard" content.gravity = Gravity.CENTER val builder = AlertDialog.Builder(this) .setTitle("Soft keyboard layering demo") .setView(content) mDialog = builder.create() mDialog!!.window!! .addFlags(FLAG_NOT_FOCUSABLE or FLAG_ALT_FOCUSABLE_IM) mDialog!!.show()
Java
TextView content = new TextView(this); content.setText("Non-editable dialog behind soft keyboard"); content.setGravity(Gravity.CENTER); final AlertDialog.Builder builder = new AlertDialog.Builder(this) .setTitle("Soft keyboard layering demo") .setView(content); mDialog = builder.create(); mDialog.getWindow() .addFlags(FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM); mDialog.show();
Tạo thành phần hiển thị lớp phủ
Tạo khung hiển thị lớp phủ bằng cách đặt cả cờ cửa sổ FLAG_NOT_FOCUSABLE
và cờ cửa sổ FLAG_ALT_FOCUSABLE_IM
:
Kotlin
val params = WindowManager.LayoutParams( width, /* Overlay window width */ height, /* Overlay window height */ WindowManager.LayoutParams.TYPE_APPLICATION, /* Overlay window type */ WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE or WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, PixelFormat.TRANSLUCENT ) params.title = "Overlay window" mOverlayView!!.layoutParams = params windowManager.addView(mOverlayView, params)
Java
WindowManager.LayoutParams params = new WindowManager.LayoutParams( width, /* Overlay window width */ height, /* Overlay window height */ TYPE_APPLICATION, /* Overlay window type */ FLAG_NOT_FOCUSABLE | FLAG_ALT_FOCUSABLE_IM, PixelFormat.TRANSLUCENT); params.setTitle("Overlay window"); mOverlayView.setLayoutParams(params); getWindowManager().addView(mOverlayView, params);