Để giúp làm rõ sự điên rồ này, tôi muốn bắt đầu bằng cách xin lỗi thay mặt cho tất cả người dùng Android vì cách đối xử hết sức lố bịch của bàn phím mềm. Lý do có rất nhiều câu trả lời, mỗi câu trả lời khác nhau, cho cùng một câu hỏi đơn giản là vì API này, giống như nhiều người khác trong Android, được thiết kế khủng khiếp. Tôi có thể nghĩ không có cách nào lịch sự để nói nó.
Tôi muốn giấu bàn phím. Tôi hy vọng sẽ cung cấp cho Android tuyên bố sau : Keyboard.hide()
. Kết thúc. Cảm ơn rât nhiều. Nhưng Android có một vấn đề. Bạn phải sử dụng InputMethodManager
để ẩn bàn phím. OK, tốt, đây là API của Android cho bàn phím. NHƯNG! Bạn được yêu cầu phải có Context
quyền truy cập vào IMM. Bây giờ chúng tôi có một vấn đề. Tôi có thể muốn ẩn bàn phím khỏi một lớp tĩnh hoặc tiện ích không sử dụng hoặc không cần sử dụng Context
. hoặc Và FAR tệ hơn, IMM yêu cầu bạn chỉ định những gì View
(hoặc thậm chí tệ hơn, những gì Window
) bạn muốn ẩn bàn phím TỪ.
Đây là những gì làm cho việc ẩn bàn phím rất khó khăn. Google thân mến: Khi tôi đang tìm công thức làm bánh, không có nơi nào RecipeProvider
trên trái đất có thể từ chối cung cấp cho tôi công thức đó trừ khi tôi trả lời đầu tiên WHO sẽ ăn bánh VÀ nơi nó sẽ được ăn !!
Câu chuyện buồn này kết thúc với một sự thật xấu xí: để ẩn bàn phím Android, bạn sẽ được yêu cầu cung cấp 2 hình thức nhận dạng: a Context
và a View
hoặc a Window
.
Tôi đã tạo ra một phương thức tiện ích tĩnh có thể thực hiện công việc RẤT vững chắc, miễn là bạn gọi nó từ một Activity
.
public static void hideKeyboard(Activity activity) {
InputMethodManager imm = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
//Find the currently focused view, so we can grab the correct window token from it.
View view = activity.getCurrentFocus();
//If no view currently has focus, create a new one, just so we can grab a window token from it
if (view == null) {
view = new View(activity);
}
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
Xin lưu ý rằng phương thức tiện ích này CHỈ hoạt động khi được gọi từ một Activity
! Các cuộc gọi phương thức trên getCurrentFocus
của mục tiêu Activity
để lấy mã thông báo cửa sổ thích hợp.
Nhưng giả sử bạn muốn ẩn bàn phím khỏi máy EditText
chủ lưu trữ trong DialogFragment
? Bạn không thể sử dụng phương pháp trên cho điều đó:
hideKeyboard(getActivity()); //won't work
Điều này sẽ không hoạt động vì bạn sẽ chuyển tham chiếu đến Fragment
máy chủ lưu trữ Activity
, điều này sẽ không có quyền kiểm soát tập trung trong khi Fragment
hiển thị! Ồ Vì vậy, để ẩn bàn phím khỏi các mảnh vỡ, tôi dùng đến cấp độ thấp hơn, phổ biến hơn và xấu hơn:
public static void hideKeyboardFrom(Context context, View view) {
InputMethodManager imm = (InputMethodManager) context.getSystemService(Activity.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
Dưới đây là một số thông tin bổ sung lượm lặt được từ việc lãng phí nhiều thời gian hơn để theo đuổi giải pháp này:
Giới thiệu về windowSoftInputMode
Vẫn còn một điểm tranh cãi nữa cần phải biết. Theo mặc định, Android sẽ tự động gán tiêu điểm ban đầu cho EditText
điều khiển đầu tiên hoặc có thể lấy nét trong của bạn Activity
. Theo tự nhiên, InputMethod (thường là bàn phím mềm) sẽ phản hồi lại sự kiện lấy nét bằng cách hiển thị chính nó. Các windowSoftInputMode
thuộc tính trong AndroidManifest.xml
khi thiết lập để stateAlwaysHidden
, chỉ thị bàn phím để bỏ qua trọng tâm ban đầu tự giao này.
<activity
android:name=".MyActivity"
android:windowSoftInputMode="stateAlwaysHidden"/>
Hầu như không thể tin được, nó dường như không làm gì để ngăn bàn phím mở khi bạn chạm vào điều khiển (trừ khi focusable="false"
và / hoặc focusableInTouchMode="false"
được gán cho điều khiển). Rõ ràng, cài đặt windowSoftInputMode chỉ áp dụng cho các sự kiện lấy nét tự động, không áp dụng cho các sự kiện lấy nét được kích hoạt bởi các sự kiện chạm.
Do đó, stateAlwaysHidden
RẤT kém tên thực sự. Nó có lẽ nên được gọi ignoreInitialFocus
thay thế.
Hi vọng điêu nay co ich.
CẬP NHẬT: Nhiều cách khác để nhận mã thông báo cửa sổ
Nếu không có chế độ xem tập trung (ví dụ: có thể xảy ra nếu bạn chỉ thay đổi các đoạn), có các chế độ xem khác sẽ cung cấp mã thông báo cửa sổ hữu ích.
Đây là những lựa chọn thay thế cho đoạn mã trên if (view == null) view = new View(activity);
Những điều này không đề cập rõ ràng đến hoạt động của bạn.
Bên trong một lớp phân mảnh:
view = getView().getRootView().getWindowToken();
Cho một đoạn fragment
như một tham số:
view = fragment.getView().getRootView().getWindowToken();
Bắt đầu từ nội dung của bạn:
view = findViewById(android.R.id.content).getRootView().getWindowToken();
CẬP NHẬT 2: Xóa tiêu điểm để tránh hiển thị lại bàn phím nếu bạn mở ứng dụng từ nền
Thêm dòng này vào cuối phương thức:
view.clearFocus();