Xử lý chế độ hiển thị phương thức nhập

Khi tiêu điểm nhập di chuyển vào hoặc ra khỏi trường văn bản có thể chỉnh sửa, Android sẽ hiển thị hoặc ẩn nội dung nhập — chẳng hạn như bàn phím ảo — như 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 ở trên phương thức nhập. Ví dụ: khi không gian dọc trên màn hình là bị hạn chế, trường văn bản có thể lấp đầy tất cả không gian phía trên phương thức nhập.

Đối với hầu hết ứng dụng, đây là tất cả những hành vi mặc định cần thiết. Trong một số trường hợp, tuy nhiên, bạn có thể muốn kiểm soát nhiều hơn mức hiển thị của phương thức nhập và tác động như thế nào đến bố cục. Bài học này sẽ giải thích cách kiểm soát và ứng phó với chế độ hiển thị của phương thức nhập.

Hiển thị 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 khi hoạt động bắt đầu sẽ không hiện bàn phím mềm. Đây là hành vi 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 nhập văn bản thực sự là tác vụ chính, chẳng hạn như trên màn hình đăng nhập, thì bạn có thể muố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 phương thức android:windowSoftInputMode cho thuộc tính Phần tử <activity> có 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, bàn phím sẽ giảm dung lượng có sẵn 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 chế độ 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 hành vi tốt nhất cho ứng dụng của bạn, hãy chỉ định cách bạn muốn hệ thống hiển thị giao diện người dùng trong dung lượng 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 phương thức Thuộc tính android:windowSoftInputMode trong phần tử <activity> của tệp kê khai bằng một trong các nút điều chỉnh giá trị.

Ví dụ: để đảm bảo rằng hệ thống đổi kích thước bố cục của bạn theo giúp giữ cho tất cả nội dung bố cục đều có thể truy cập được, ngay cả khi yêu cầu cuộn—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 bàn phím mềm ban đầu mức độ hiển thị cụ thể từ 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 có các chế độ điều khiển mà người dùng có thể cần truy cập ngay sau hoặc trong khi thực hiện nhập văn bản. Cho 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, 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 thị 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 hiển thị, bạn có thể sử dụng InputMethodManager để hiện nội dung.

Ví dụ: phương thức sau đây sẽ lấy View mà trong đó người dùng dự kiến sẽ nhập nội dung nào đó, gọi requestFocus() để cung cấp 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 thị bàn phím mềm một cách đáng tin cậy

Có một số trường hợp nhất định, chẳng hạn như khi một hoạt động bắt đầu, trong đó đang dùng InputMethodManager.showSoftInput() để hiện bàn phím mềm có thể khiến người dùng không thấy bàn phím phần mềm.

Khả năng hiển thị của bàn phím mềm khi sử dụng showSoftInput() phụ thuộc vào về 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ều này lần lượt là yêu cầu đặt cửa sổ phải làm tâm điểm và trình chỉnh sửa để yêu cầu lấy tiêu điểm khung hiển thị bằng View.requestFocus()).

  • Khả năng hiển thị cũng có thể bị ảnh hưởng bởi android:windowSoftInputMode và cờ mà showSoftInput() sử dụng.

Trong một số trường hợp sử dụng, chẳng hạn như khi một hoạt động bắt đầu, một vài thì không được đáp ứng các điều kiện bắt buộc. Hệ thống không coi chế độ xem này là kết nối với bàn phím phần mềm, bỏ qua lệnh gọi showSoftInput(), và người dùng không thấy bàn phím mềm.

Để đả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 cách sau lựa chọn thay thế:

  • (Nên dùng) Sử dụng WindowInsetsControllerCompat. Đối tượng này hiển thị bàn phím mềm trong Activity.onCreate() như minh hoạ trong đoạn mã sau. Cuộc gọi sẽ được lên lịch sau thời hạn sẽ được đặt 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 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ọi showSoftInput().

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ờ chế độ 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ố gắn cờ các giá trị vào các phương thức này. Ví dụ: nếu ứng dụng mong muốn bàn phím mềm hiện lên khi gọi View.getWindowInsetsController().show(ime())Activity.onCreate() trong khoảng thời gian hoạt động bắt đầu, nhà phát triển ứng dụng nên thận trọng để không đặt Cờ SOFT_INPUT_STATE_HIDDEN hoặc SOFT_INPUT_STATE_ALWAYS_HIDDEN trong lần đầu khởi chạy để 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. Chiến dịch 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 trong 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ặc SOFT_INPUT_STATE_ALWAYS_HIDDEN khi thành phần hiển thị lấy được tiêu điểm.

Ẩn bàn phím mềm theo cách thủ công dựa trên hành vi trước đó của hệ thống

Trong một số trường hợp, ứng dụng của bạn phải ẩn bàn phím mềm theo cách thủ công ví dụ: khi trường văn bản 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 độ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 thị rõ ràng hoặc ngầm ẩn:

  • Bàn phím mềm được coi là đã hiển thị rõ ràng sau một cuộc gọi đến 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 đã vượt qua SHOW_IMPLICIT đến showSoftInput().

Thông thường, hideSoftInputFromWindow() sẽ ẩn bàn phím mềm bất kể cách yêu cầu nhưng với HIDE_IMPLICIT_ONLY bạn chỉ có thể đóng một bàn phím mềm được yêu cầu ngầm.

Hiện hộp thoại hoặc chế độ xem lớp phủ ở trên 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 thuộc tính không thể chỉnh sửa hộp thoại hoặc cửa sổ phủ lên trên bàn phím mềm.

Ứng dụng của bạn có một số tuỳ chọn mà các phần sau đây mô tả.

Tóm lại, hãy đảm bảo xử lý chính xác cờ cửa sổ của bàn phím mềm nhắm mục tiêu cửa sổ sao cho đáp ứng các kỳ vọng sau về thứ tự dọc (lớp z):

  • Không có cờ (trường hợp thông thường): Phía sau lớp bàn phím mềm và có thể nhận văn bản.
  • FLAG_NOT_FOCUSABLE : Ở trên 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 kết nối với bàn phím mềm. Đồng thời chặn tất cả các chế độ xem bên dưới đó kết nối với bàn phím mềm. Điều này rất hữu ích khi hiển thị hộp thoại ứng dụng không sử dụng văn bản phương thức nhập phía trên lớp bàn phím mềm.
  • FLAG_NOT_FOCUSABLEFLAG_ALT_FOCUSABLE_IM : Phía sau lớp bàn phím mềm, nhưng không thể nhận văn bản.
  • FLAG_NOT_FOCUSABLEFLAG_NOT_TOUCH_MODAL : Ở phía trên bàn phím mềm và cho phép "thực hiện" các sự kiện chạm cửa sổ lên bàn phím mềm.

Tạo hộp thoại

Sử dụng FLAG_ALT_FOCUSABLE_IM cờ cửa sổ hộp thoại để giữ hộp thoại nằm trên 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 chế độ xem lớp phủ

Tạo chế độ xem lớp phủ chỉ định TYPE_APPLICATION_OVERLAY loại cửa sổ và FLAG_ALT_FOCUSABLE_IM gắn cờ cửa sổ 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 thị 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 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 do hoạt động của trình chỉnh sửa yêu cầu để chữ ký 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 thành điều chỉnh bố cục của cửa sổ hoặc hộp thoại.

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 mô tả các lựa chọn này.

Tạo hộp thoại

Tạo hộp thoại bằng cách đặt cả FLAG_NOT_FOCUSABLE cờ hiệu cho cửa sổ và FLAG_ALT_FOCUSABLE_IM cờ cho cửa sổ:

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 chế độ xem lớp phủ

Tạo chế độ xem lớp phủ bằng cách đặt cả FLAG_NOT_FOCUSABLE cờ hiệu cho cửa sổ và FLAG_ALT_FOCUSABLE_IM cờ cho cửa sổ:

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