Tôi cần phải làm một việc rất đơn giản - tìm hiểu xem bàn phím phần mềm có được hiển thị không. Điều này có thể có trong Android?
Tôi cần phải làm một việc rất đơn giản - tìm hiểu xem bàn phím phần mềm có được hiển thị không. Điều này có thể có trong Android?
Câu trả lời:
TRẢ LỜI MỚI được thêm vào ngày 25 tháng 1 năm 2012
Kể từ khi viết câu trả lời dưới đây, ai đó đã theo dõi tôi về sự tồn tại của ViewTreeObserver và bạn bè, các API đã ẩn trong SDK kể từ phiên bản 1.
Thay vì yêu cầu loại Bố cục tùy chỉnh, một giải pháp đơn giản hơn nhiều là cung cấp cho chế độ xem gốc của hoạt động của bạn một ID đã biết, giả sử @+id/activityRoot
, móc GlobalLayoutListener vào ViewTreeObserver và từ đó tính toán kích thước khác nhau giữa gốc xem hoạt động của bạn và kích thước cửa sổ:
final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
if (heightDiff > dpToPx(this, 200)) { // if more than 200 dp, it's probably a keyboard...
// ... do something here
}
}
});
Sử dụng một tiện ích như:
public static float dpToPx(Context context, float valueInDp) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, valueInDp, metrics);
}
Dễ dàng!
Lưu ý:
Ứng dụng của bạn phải đặt cờ này trong Bản kê khai Android android:windowSoftInputMode="adjustResize"
nếu không giải pháp trên sẽ không hoạt động.
CÂU TRẢ LỜI
Vâng, điều đó là có thể, nhưng nó khó hơn nhiều so với nó.
Nếu tôi cần quan tâm khi bàn phím xuất hiện và biến mất (điều này khá thường xuyên) thì việc tôi làm là tùy chỉnh lớp bố cục cấp cao nhất của mình thành một lớp ghi đè onMeasure()
. Logic cơ bản là nếu bố cục thấy mình lấp đầy ít hơn đáng kể so với tổng diện tích của cửa sổ, thì có lẽ một bàn phím mềm sẽ hiển thị.
import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.widget.LinearLayout;
/*
* LinearLayoutThatDetectsSoftKeyboard - a variant of LinearLayout that can detect when
* the soft keyboard is shown and hidden (something Android can't tell you, weirdly).
*/
public class LinearLayoutThatDetectsSoftKeyboard extends LinearLayout {
public LinearLayoutThatDetectsSoftKeyboard(Context context, AttributeSet attrs) {
super(context, attrs);
}
public interface Listener {
public void onSoftKeyboardShown(boolean isShowing);
}
private Listener listener;
public void setListener(Listener listener) {
this.listener = listener;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = MeasureSpec.getSize(heightMeasureSpec);
Activity activity = (Activity)getContext();
Rect rect = new Rect();
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
int statusBarHeight = rect.top;
int screenHeight = activity.getWindowManager().getDefaultDisplay().getHeight();
int diff = (screenHeight - statusBarHeight) - height;
if (listener != null) {
listener.onSoftKeyboardShown(diff>128); // assume all soft keyboards are at least 128 pixels high
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
Sau đó, trong lớp Hoạt động của bạn ...
public class MyActivity extends Activity implements LinearLayoutThatDetectsSoftKeyboard.Listener {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
LinearLayoutThatDetectsSoftKeyboard mainLayout = (LinearLayoutThatDetectsSoftKeyboard)findViewById(R.id.main);
mainLayout.setListener(this);
...
}
@Override
public void onSoftKeyboardShown(boolean isShowing) {
// do whatever you need to do here
}
...
}
((ViewGroup) findViewById(android.R.id.content)).getChildAt(0)
android.R.id.content
), bạn sẽ có thể tự tin hơn nói rằng System
thay vì ứng dụng của bạn là thực thể thay đổi chiều cao của nó. Sẽ an toàn hơn nhiều cho nhóm Android khi cho chúng tôi nghỉ ngơi và cho chúng tôi biết ít nhất những điều cơ bản về đầu vào SoftPal.
heightDiff
sẽ luôn bao gồm chiều cao của thanh hành động. Trong câu trả lời mới đã bị bỏ qua bằng cách kiểm tra nếu chiều cao đó lớn hơn một số hằng số, nhưng 100 pixel là không đủ cho các thiết bị xxhdpi như Nexus 4. Cân nhắc chuyển đổi giá trị đó thành DP nếu bạn thực sự muốn sử dụng công việc hack này- xung quanh.
Vì vậy, hy vọng điều này sẽ giúp ai đó.
Câu trả lời mới mà Reuben Scratton đưa ra là rất hay và thực sự hiệu quả, nhưng nó thực sự chỉ hoạt động nếu bạn đặt windowSoftInputMode thành điều chỉnhResize. Nếu bạn đặt nó thành điều chỉnhPan, bạn vẫn không thể phát hiện xem bàn phím có hiển thị hay không bằng đoạn mã của mình. Để khắc phục điều này, tôi đã thực hiện sửa đổi nhỏ này cho đoạn mã trên.
final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
if (heightDiff > 0.25*activityRootView.getRootView().getHeight()) { // if more than 25% of the screen, its probably a keyboard...
... do something here
}
}
});
TwoDScrollerView
tương tự như stackoverflow.com/a/5224088/530513 mặc dù cũng thu phóng. Đứa trẻ không đơn giản ImageView
mà là một bố cục tùy chỉnh (mở rộng RelativeLayout
) nhưng không thể phát hiện bàn phím bằng giải pháp được đề xuất mặc dù đã cài đặt android:windowSoftInputMode="adjustResize"
. Cảm ơn!
ActionBar
và ActionBarSherlock
. Cảm ơn rất nhiều! Nhân tiện, có một phương pháp r.height()
:)
heightDiff > root.getRootView().getHeight() / 4
là giá trị tốt để làm việc với thiết bị độ phân giải cao. 100px là ngắn. trong Nexus 5 với độ phân giải 1080x1920, 1920 - (996-75)>? 100 = 999 1920 - (1776-75)>? 100 = 219 // bàn phím lên trong galaxy s2 với độ phân giải 480x800, 800 - (800-38)>? 100 = 38 800 - (410-38)>? 100 = 428 // bàn phím đã hết, số ma thuật 100px không đủ tốt.
Nó đã được mãi mãi về mặt máy tính nhưng câu hỏi này vẫn còn có liên quan không thể tin được!
Vì vậy, tôi đã thực hiện các câu trả lời ở trên và đã kết hợp và tinh chỉnh chúng một chút ...
public interface OnKeyboardVisibilityListener {
void onVisibilityChanged(boolean visible);
}
public final void setKeyboardListener(final OnKeyboardVisibilityListener listener) {
final View activityRootView = ((ViewGroup) getActivity().findViewById(android.R.id.content)).getChildAt(0);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
private boolean wasOpened;
private final int DefaultKeyboardDP = 100;
// From @nathanielwolf answer... Lollipop includes button bar in the root. Add height of button bar (48dp) to maxDiff
private final int EstimatedKeyboardDP = DefaultKeyboardDP + (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? 48 : 0);
private final Rect r = new Rect();
@Override
public void onGlobalLayout() {
// Convert the dp to pixels.
int estimatedKeyboardHeight = (int) TypedValue
.applyDimension(TypedValue.COMPLEX_UNIT_DIP, EstimatedKeyboardDP, activityRootView.getResources().getDisplayMetrics());
// Conclude whether the keyboard is shown or not.
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
boolean isShown = heightDiff >= estimatedKeyboardHeight;
if (isShown == wasOpened) {
Log.d("Keyboard state", "Ignoring global layout change...");
return;
}
wasOpened = isShown;
listener.onVisibilityChanged(isShown);
}
});
}
Làm việc cho tôi :)
LƯU Ý: Nếu bạn nhận thấy DefaultPalDP không phù hợp với thiết bị của bạn với giá trị và đăng nhận xét cho mọi người biết giá trị nào sẽ là ... cuối cùng chúng tôi sẽ nhận được giá trị chính xác để phù hợp với tất cả các thiết bị!
Để biết thêm chi tiết, hãy xem triển khai trên Cyborg
Xin lỗi vì câu trả lời muộn, nhưng tôi đã tạo ra một lớp người trợ giúp nhỏ để xử lý các sự kiện mở / đóng với thông báo cho người nghe và những điều hữu ích khác, có thể ai đó sẽ thấy hữu ích:
import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver;
import java.util.LinkedList;
import java.util.List;
public class SoftKeyboardStateWatcher implements ViewTreeObserver.OnGlobalLayoutListener {
public interface SoftKeyboardStateListener {
void onSoftKeyboardOpened(int keyboardHeightInPx);
void onSoftKeyboardClosed();
}
private final List<SoftKeyboardStateListener> listeners = new LinkedList<SoftKeyboardStateListener>();
private final View activityRootView;
private int lastSoftKeyboardHeightInPx;
private boolean isSoftKeyboardOpened;
public SoftKeyboardStateWatcher(View activityRootView) {
this(activityRootView, false);
}
public SoftKeyboardStateWatcher(View activityRootView, boolean isSoftKeyboardOpened) {
this.activityRootView = activityRootView;
this.isSoftKeyboardOpened = isSoftKeyboardOpened;
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(this);
}
@Override
public void onGlobalLayout() {
final Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);
final int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
if (!isSoftKeyboardOpened && heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
isSoftKeyboardOpened = true;
notifyOnSoftKeyboardOpened(heightDiff);
} else if (isSoftKeyboardOpened && heightDiff < 100) {
isSoftKeyboardOpened = false;
notifyOnSoftKeyboardClosed();
}
}
public void setIsSoftKeyboardOpened(boolean isSoftKeyboardOpened) {
this.isSoftKeyboardOpened = isSoftKeyboardOpened;
}
public boolean isSoftKeyboardOpened() {
return isSoftKeyboardOpened;
}
/**
* Default value is zero {@code 0}.
*
* @return last saved keyboard height in px
*/
public int getLastSoftKeyboardHeightInPx() {
return lastSoftKeyboardHeightInPx;
}
public void addSoftKeyboardStateListener(SoftKeyboardStateListener listener) {
listeners.add(listener);
}
public void removeSoftKeyboardStateListener(SoftKeyboardStateListener listener) {
listeners.remove(listener);
}
private void notifyOnSoftKeyboardOpened(int keyboardHeightInPx) {
this.lastSoftKeyboardHeightInPx = keyboardHeightInPx;
for (SoftKeyboardStateListener listener : listeners) {
if (listener != null) {
listener.onSoftKeyboardOpened(keyboardHeightInPx);
}
}
}
private void notifyOnSoftKeyboardClosed() {
for (SoftKeyboardStateListener listener : listeners) {
if (listener != null) {
listener.onSoftKeyboardClosed();
}
}
}
}
Ví dụ sử dụng:
final SoftKeyboardStateWatcher softKeyboardStateWatcher
= new SoftKeyboardStateWatcher(findViewById(R.id.activity_main_layout);
// Add listener
softKeyboardStateWatcher.addSoftKeyboardStateListener(...);
// then just handle callbacks
getLastKeyboardHeightInPx()
không bao gồm chiều cao của hàng đó. Bạn có biết một cách để đưa nó vào tài khoản là tốt?
Một số cải tiến để tránh phát hiện sai tầm nhìn của bàn phím mềm trên các thiết bị mật độ cao:
Ngưỡng chênh lệch chiều cao phải được xác định là 128 dp , không phải 128 pixel .
Tham khảo tài liệu thiết kế của Google về Metrics và Grid , 48 dp là kích thước thoải mái cho đối tượng cảm ứng và 32 dp là tối thiểu cho các nút. Bàn phím mềm chung phải bao gồm 4 hàng nút phím, vì vậy chiều cao bàn phím tối thiểu phải là: 32 dp * 4 = 128 dp , có nghĩa là kích thước ngưỡng sẽ chuyển sang pixel bằng cách nhân mật độ thiết bị. Đối với các thiết bị xxxhdpi (mật độ 4), ngưỡng chiều cao bàn phím mềm phải là 128 * 4 = 512 pixel.
Chênh lệch chiều cao giữa chế độ xem gốc và khu vực hiển thị của nó:
chiều cao của chế độ xem gốc - chiều cao của thanh trạng thái - chiều cao khung nhìn thấy = đáy khung nhìn gốc - đáy khung hiển thị, vì chiều cao của thanh trạng thái bằng với đỉnh của khung nhìn thấy gốc.
private final String TAG = "TextEditor";
private TextView mTextEditor;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_editor);
mTextEditor = (TextView) findViewById(R.id.text_editor);
mTextEditor.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
isKeyboardShown(mTextEditor.getRootView());
}
});
}
private boolean isKeyboardShown(View rootView) {
/* 128dp = 32dp * 4, minimum button height 32dp and generic 4 rows soft keyboard */
final int SOFT_KEYBOARD_HEIGHT_DP_THRESHOLD = 128;
Rect r = new Rect();
rootView.getWindowVisibleDisplayFrame(r);
DisplayMetrics dm = rootView.getResources().getDisplayMetrics();
/* heightDiff = rootView height - status bar height (r.top) - visible frame height (r.bottom - r.top) */
int heightDiff = rootView.getBottom() - r.bottom;
/* Threshold size: dp to pixels, multiply with display density */
boolean isKeyboardShown = heightDiff > SOFT_KEYBOARD_HEIGHT_DP_THRESHOLD * dm.density;
Log.d(TAG, "isKeyboardShown ? " + isKeyboardShown + ", heightDiff:" + heightDiff + ", density:" + dm.density
+ "root view height:" + rootView.getHeight() + ", rect:" + r);
return isKeyboardShown;
}
Tôi đã sử dụng một ít thời gian để tìm hiểu điều này ... Tôi đã chạy nó một số CastExceptions, nhưng đã tìm ra rằng bạn có thể thay thế bạn linearLayout trong layout.xml bằng tên của lớp.
Như thế này:
<?xml version="1.0" encoding="UTF-8"?>
<LinearLayout android:layout_width="fill_parent" android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/llMaster">
<com.ourshoppingnote.RelativeLayoutThatDetectsSoftKeyboard android:background="@drawable/metal_background"
android:layout_width="fill_parent" android:layout_height="fill_parent"
android:id="@+id/rlMaster" >
<LinearLayout android:layout_width="fill_parent"
android:layout_height="1dip" android:background="@drawable/line"></LinearLayout>
....
</com.ourshoppingnote.RelativeLayoutThatDetectsSoftKeyboard>
</LinearLayout>
Bằng cách đó, bạn không gặp phải bất kỳ vấn đề nào.
... Và nếu bạn không muốn làm điều này trên mỗi trang, tôi khuyên bạn nên sử dụng "MasterPage trong Android". Xem liên kết tại đây: http://jnastase.alner.net/archive/2011/01/08/ldquomaster-pagesrdquo-in-android.aspx
Kiểm tra chiều cao của các yếu tố là không đáng tin cậy vì một số bàn phím như WifiPal có chiều cao bằng không.
Thay vào đó, bạn có thể sử dụng kết quả gọi lại của showSoftInput () và hideSoftInput () để kiểm tra trạng thái của bàn phím. Chi tiết đầy đủ và mã ví dụ tại
https://rogerkeays.com/how-to-check-if-the-software-keyboard-is-shown-in-android
Ý tưởng là, nếu bạn cần ẩn bàn phím và kiểm tra trạng thái nhập mềm cùng một lúc, hãy sử dụng giải pháp sau:
public boolean hideSoftInput() {
InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);
}
Phương pháp này trả về true nếu bàn phím được hiển thị trước khi ẩn.
Tôi thấy rằng sự kết hợp của phương pháp @ Reuben_Scratton cùng với phương pháp của @ Yogesh dường như hoạt động tốt nhất. Kết hợp các phương pháp của họ sẽ mang lại một cái gì đó như thế này:
final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (getResources().getConfiguration().keyboardHidden == Configuration.KEYBOARDHIDDEN_NO) { // Check if keyboard is not hidden
// ... do something here
}
}
});
Bạn có thể quan sát ẩn của phím chức năng bằng cách sử dụng decorView của hoạt động.
public final class SoftKeyboardUtil {
public static final String TAG = "SoftKeyboardUtil";
public static void observeSoftKeyBoard(Activity activity , final OnSoftKeyBoardHideListener listener){
final View decorView = activity.getWindow().getDecorView();
decorView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect rect = new Rect();
decorView.getWindowVisibleDisplayFrame(rect);
int displayHight = rect.bottom - rect.top;
int hight = decorView.getHeight();
boolean hide = (double)displayHight / hight > 0.8 ;
if(Log.isLoggable(TAG, Log.DEBUG)){
Log.d(TAG ,"DecorView display hight = "+displayHight);
Log.d(TAG ,"DecorView hight = "+ hight);
Log.d(TAG, "softkeyboard visible = " + !hide);
}
listener.onSoftKeyBoardVisible(!hide);
}
});
}
public interface OnSoftKeyBoardHideListener{
void onSoftKeyBoardVisible(boolean visible);
}
}
Thay vì giả định mã hóa khác biệt, tôi đã làm một cái gì đó như thế này, vì tôi không có các tùy chọn menu trong ứng dụng của mình.
final View root= findViewById(R.id.myrootview);
root.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int heightDiff = root.getRootView().getHeight() - root.getHeight();
Rect rectgle= new Rect();
Window window= getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
int contentViewTop=
window.findViewById(Window.ID_ANDROID_CONTENT).getTop();
if(heightDiff <= contentViewTop){
//Soft KeyBoard Hidden
}else{
//Soft KeyBoard Shown
}
}
});
Ngoài ra còn có giải pháp với phần tử hệ thống, nhưng nó chỉ hoạt động với API >= 21
( Android L
). Giả sử bạn có BottomNavigationView
, là con của LinearLayout
và bạn cần ẩn nó khi bàn phím được hiển thị:
> LinearLayout
> ContentView
> BottomNavigationView
Tất cả bạn cần làm là mở rộng LinearLayout
theo cách như vậy:
public class KeyboardAwareLinearLayout extends LinearLayout {
public KeyboardAwareLinearLayout(Context context) {
super(context);
}
public KeyboardAwareLinearLayout(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public KeyboardAwareLinearLayout(Context context,
@Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public KeyboardAwareLinearLayout(Context context, AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
int childCount = getChildCount();
for (int index = 0; index < childCount; index++) {
View view = getChildAt(index);
if (view instanceof BottomNavigationView) {
int bottom = insets.getSystemWindowInsetBottom();
if (bottom >= ViewUtils.dpToPx(200)) {
// keyboard is shown
view.setVisibility(GONE);
} else {
// keyboard is hidden
view.setVisibility(VISIBLE);
}
}
}
return insets;
}
}
Ý tưởng là khi bàn phím được hiển thị, các phần tử hệ thống được thay đổi với .bottom
giá trị khá lớn .
Có một phương pháp ẩn có thể giúp cho việc này InputMethodManager.getInputMethodWindowVisibleHeight
. Nhưng tôi không biết tại sao nó lại bị ẩn.
import android.content.Context
import android.os.Handler
import android.view.inputmethod.InputMethodManager
class SoftKeyboardStateWatcher(private val ctx: Context) {
companion object {
private const val DELAY = 10L
}
private val handler = Handler()
private var isSoftKeyboardOpened: Boolean = false
private val height: Int
get() {
val imm = ctx.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
val method = imm.javaClass.getMethod("getInputMethodWindowVisibleHeight")
method.isAccessible = true
return method.invoke(imm) as Int
}
private val task: Runnable by lazy {
Runnable {
start()
if (!isSoftKeyboardOpened && height > 0) {
isSoftKeyboardOpened = true
notifyOnSoftKeyboardOpened(height)
} else if (isSoftKeyboardOpened && height == 0) {
isSoftKeyboardOpened = false
notifyOnSoftKeyboardClosed()
}
}
}
var listener: SoftKeyboardStateListener? = null
interface SoftKeyboardStateListener {
fun onSoftKeyboardOpened(keyboardHeightInPx: Int)
fun onSoftKeyboardClosed()
}
fun start() {
handler.postDelayed(task, DELAY)
}
fun stop() {
handler.postDelayed({
if (!isSoftKeyboardOpened) handler.removeCallbacks(task)
}, DELAY * 10)
}
private fun notifyOnSoftKeyboardOpened(keyboardHeightInPx: Int) {
listener?.onSoftKeyboardOpened(keyboardHeightInPx)
}
private fun notifyOnSoftKeyboardClosed() {
listener?.onSoftKeyboardClosed()
}
}
Không có giải pháp nào trong số này sẽ hoạt động cho Lollipop. Trong Lollipop activityRootView.getRootView().getHeight()
bao gồm chiều cao của thanh nút, trong khi đo chế độ xem thì không. Tôi đã điều chỉnh giải pháp tốt nhất / đơn giản nhất ở trên để làm việc với Lollipop.
final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
Resources res = getResources();
// The status bar is 25dp, use 50dp for assurance
float maxDiff =
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, res.getDisplayMetrics());
//Lollipop includes button bar in the root. Add height of button bar (48dp) to maxDiff
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
float buttonBarHeight =
TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 48, res.getDisplayMetrics());
maxDiff += buttonBarHeight;
}
if (heightDiff > maxDiff) { // if more than 100 pixels, its probably a keyboard...
...do something here
}
}
});
Tôi vừa gặp một lỗi trong khi sử dụng hầu hết các giải pháp ở trên đề nghị thêm một số cố định.
S4 có dpi cao dẫn đến chiều cao của thanh điều hướng là 100px, do đó ứng dụng của tôi nghĩ rằng bàn phím luôn mở.
Vì vậy, với tất cả các điện thoại độ phân giải cao mới được phát hành, tôi tin rằng sử dụng giá trị mã hóa cứng không phải là ý tưởng tốt trong dài hạn.
Một cách tiếp cận tốt hơn mà tôi tìm thấy sau một số thử nghiệm trên các màn hình và thiết bị khác nhau là sử dụng tỷ lệ phần trăm. Nhận sự khác biệt giữa nội dung ứng dụng decorView và ur và sau đó kiểm tra tỷ lệ phần trăm của sự khác biệt đó là bao nhiêu. Từ các số liệu thống kê mà tôi có, hầu hết các thanh điều hướng (bất kể kích thước, độ phân giải, v.v.) sẽ chiếm từ 3% đến 5% màn hình. Nếu như bàn phím đang mở, nó chiếm từ 47% đến 55% màn hình.
Để kết luận, giải pháp của tôi là kiểm tra xem độ lệch có lớn hơn 10% hay không thì tôi giả sử nó là bàn phím mở.
Tôi đã sử dụng một biến thể nhỏ của câu trả lời của Reuban, điều này tỏ ra hữu ích hơn trong một số trường hợp nhất định, đặc biệt là với các thiết bị có độ phân giải cao.
final View activityRootView = findViewById(android.R.id.content);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(
new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int heightView = activityRootView.getHeight();
int widthView = activityRootView.getWidth();
if (1.0 * widthView / heightView > 3) {
//Make changes for Keyboard not visible
} else {
//Make changes for keyboard visible
}
}
});
R.id.activityRoot
, bạn chỉ cần sử dụng android.R.id.content
chính xác những gì bạn cần.
Nó đã được mãi mãi về mặt máy tính nhưng câu hỏi này vẫn còn có liên quan không thể tin được! Vì vậy, tôi đã thực hiện các câu trả lời ở trên và đã kết hợp và tinh chỉnh chúng một chút ...
public interface OnKeyboardVisibilityListener {
void onVisibilityChanged(boolean visible);
}
public final void setKeyboardListener(final OnKeyboardVisibilityListener listener) {
final View activityRootView = ((ViewGroup) getActivity().findViewById(android.R.id.content)).getChildAt(0);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
private boolean wasOpened;
private final Rect r = new Rect();
@Override
public void onGlobalLayout() {
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
boolean isOpen = heightDiff > 100;
if (isOpen == wasOpened) {
logDebug("Ignoring global layout change...");
return;
}
wasOpened = isOpen;
listener.onVisibilityChanged(isOpen);
}
});
}
Nó làm việc cho tôi.
Thử cái này:
final View activityRootView = getWindow().getDecorView().getRootView();
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
if (heightDiff < activityRootView.getRootView().getHeight() / 4 ) { // if more than 100 pixels, its probably a keyboard...
// ... do something here ... \\
}
}
});
Câu trả lời của tôi về cơ bản giống như câu trả lời của Kachi, nhưng tôi đã gói nó vào một lớp người trợ giúp tốt đẹp để dọn dẹp cách nó được sử dụng trong suốt ứng dụng của tôi.
import android.app.Activity;
import android.app.Fragment;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
/**
* Detects Keyboard Status changes and fires events only once for each change
*/
public class KeyboardStatusDetector {
KeyboardVisibilityListener visibilityListener;
boolean keyboardVisible = false;
public void registerFragment(Fragment f) {
registerView(f.getView());
}
public void registerActivity(Activity a) {
registerView(a.getWindow().getDecorView().findViewById(android.R.id.content));
}
public KeyboardStatusDetector registerView(final View v) {
v.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
v.getWindowVisibleDisplayFrame(r);
int heightDiff = v.getRootView().getHeight() - (r.bottom - r.top);
if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
/** Check this variable to debounce layout events */
if(!keyboardVisible) {
keyboardVisible = true;
if(visibilityListener != null) visibilityListener.onVisibilityChanged(true);
}
} else {
if(keyboardVisible) {
keyboardVisible = false;
if(visibilityListener != null) visibilityListener.onVisibilityChanged(false);
}
}
}
});
return this;
}
public KeyboardStatusDetector setVisibilityListener(KeyboardVisibilityListener listener) {
visibilityListener = listener;
return this;
}
public static interface KeyboardVisibilityListener {
public void onVisibilityChanged(boolean keyboardVisible);
}
}
Bạn có thể sử dụng điều này để phát hiện các thay đổi bàn phím ở bất cứ đâu trong suốt ứng dụng như thế này:
new KeyboardStatusDetector()
.registerFragment(fragment) //register to a fragment
.registerActivity(activity) //or register to an activity
.registerView(view) //or register to a view
.setVisibilityListener(new KeyboardVisibilityListener() {
@Override
public void onVisibilityChanged(boolean keyboardVisible) {
if(keyboardVisible) {
//Do stuff for keyboard visible
}else {
//Do stuff for keyboard hidden
}
}
});
Lưu ý: chỉ sử dụng một trong các cuộc gọi "đăng ký". Tất cả đều hoạt động như nhau và chỉ ở đó để thuận tiện
bạn có thể thử điều này, làm việc tuyệt vời cho tôi:
InputMethodManager imm = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm.isAcceptingText()) {
//Software Keyboard was shown..
} else {
//Software Keyboard was not shown..
}
Tôi gặp khó khăn trong việc duy trì trạng thái bàn phím khi thay đổi hướng của các mảnh trong chế độ xem. Tôi không chắc tại sao, nhưng nó dường như rất mạnh mẽ và hoạt động khác với một Hoạt động tiêu chuẩn.
Để duy trì trạng thái bàn phím trong trường hợp này, trước tiên bạn nên thêm android:windowSoftInputMode = "stateUnchanged"
vào AndroidManifest.xml
. Tuy nhiên, bạn có thể nhận thấy rằng điều này thực sự không giải quyết được toàn bộ vấn đề - bàn phím không mở cho tôi nếu nó được mở trước đó trước khi thay đổi hướng. Trong tất cả các trường hợp khác, hành vi dường như là chính xác.
Sau đó, chúng ta cần thực hiện một trong những giải pháp được đề cập ở đây. Công cụ sạch nhất mà tôi tìm thấy là của George Maisuradze - sử dụng hàm gọi lại boolean từ hideSoftInputFromWindow:
InputMethodManager imm = (InputMethodManager) getSystemService(Activity.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(mViewPager.getWindowToken(), 0);
Tôi đã lưu trữ giá trị này trong onSaveInstanceState
phương thức của Fragment và lấy nó onCreate
. Sau đó, tôi buộc phải hiển thị bàn phím onCreateView
nếu nó có giá trị true
(nó trả về đúng nếu bàn phím hiển thị trước khi thực sự ẩn bàn phím trước khi phá hủy Fragment).
Đây là giải pháp của tôi, và nó hoạt động. Thay vì tìm kích thước pixel, chỉ cần kiểm tra xem chiều cao của chế độ xem nội dung có thay đổi hay không:
// Scroll to the latest comment whenever the keyboard is shown
commentsContent.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
private int oldHeight;
@Override
public void onGlobalLayout() {
int newHeight = commentsContent.getMeasuredHeight();
if (newHeight < oldHeight) {
// Check for the keyboard showing in case the height difference
// is a result of orientation change
if (isSoftKeyboardShowing(CommentsActivity.this)) {
// Keyboard is showing so scroll to the latest comment
scrollToLatestComment();
}
}
oldHeight = newHeight;
}
});
public static boolean isSoftKeyboardShowing(Activity activity) {
InputMethodManager inputMethodManager = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
return inputMethodManager.isActive();
}
Đừng tạo bất kỳ mã cứng nào. Cách tốt nhất là bạn phải thay đổi kích thước lượt xem của mình trong khi tập trung vào EditText với KeyBord Show. Bạn có thể thực hiện việc thêm thay đổi kích thước thuộc tính trên hoạt động vào tệp Manifest bằng mã bên dưới.
android:windowSoftInputMode="adjustResize"
Có một phương pháp trực tiếp để tìm ra điều này. Và, nó không yêu cầu bất kỳ thay đổi Bố cục.
Vì vậy, nó cũng hoạt động ở chế độ toàn màn hình.
Mẹo nhỏ là bạn cố gắng ẩn hoặc hiển thị bàn phím mềm và nắm bắt kết quả của lần thử đó.
Không hoảng loạn, điều này không thực sự hiển thị hoặc ẩn bàn phím. Chúng tôi chỉ yêu cầu nhà nước.
Để luôn cập nhật, bạn chỉ cần lặp lại thao tác, ví dụ cứ sau 200 mili giây, sử dụng Trình xử lý.
Bạn tìm thấy một triển khai ở đây: https://stackoverflow.com/a/27567074/2525452
Tôi nghĩ rằng phương pháp này sẽ giúp bạn tìm ra liệu keybord có hiển thị hay không.
public Boolean isSoftKeyBoardVisible(){
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm.isAcceptingText()) {
Log.d(TAG,"Software Keyboard was shown");
return true;
} else {
Log.d(TAG,"Software Keyboard was not shown");
return false;
}
}
Câu trả lời mới của Reuben Scratton (tính toán Chiều cao int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
) sẽ không hoạt động nếu bạn đặt chế độ thanh trạng thái mờ.
nếu bạn sử dụng thanh trạng thái mờ, activityRootView.getHeight()
sẽ không bao giờ thay đổi thời tiết, bàn phím mềm sẽ hiển thị. nó sẽ luôn trả về chiều cao của hoạt động và thanh trạng thái.
Ví dụ: Nexus 4, Android 5.0.1, được đặt android:windowTranslucentStatus
thành true, nó sẽ trả về 1184 mãi mãi, ngay cả ime cũng có ý kiến phản đối. Nếu bạn đặtandroid:windowTranslucentStatus
thành false, nó sẽ trả về Chiều cao chính xác, nếu ẩn, nó sẽ trả về 1134 (không bao gồm thanh trạng thái) hãy đóng ime, nó sẽ trả về 5xx có thể (tùy thuộc vào chiều cao của ime)
Tôi không biết thời tiết này là một lỗi, tôi đã thử trên 4.4.4 và 5.0.1, kết quả là như nhau.
Vì vậy, cho đến nay, câu trả lời đồng ý thứ hai, giải pháp của Kachi sẽ là cách an toàn nhất để tính chiều cao của ime. Đây là một bản sao:
final View activityRootView = findViewById(R.id.activityRoot);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
if (heightDiff > 100) { // if more than 100 pixels, its probably a keyboard...
... do something here
}
}
});
Một phương pháp mà không cần LayoutListener
Trong trường hợp của tôi, tôi muốn lưu trạng thái của bàn phím trước khi thay thế Fragment của mình. Tôi gọi phương thức hideSoftInputFromWindow từonSaveInstanceState
đó, nó đóng bàn phím và trả về cho tôi xem bàn phím có nhìn thấy được hay không.
Phương pháp này đơn giản nhưng có thể thay đổi trạng thái bàn phím của bạn.
Tôi biết rằng đây là một bài viết cũ nhưng tôi nghĩ đây là cách tiếp cận đơn giản nhất mà tôi biết và thiết bị thử nghiệm của tôi là Nexus 5. Tôi chưa thử nó ở các thiết bị khác. Hy vọng rằng những người khác sẽ chia sẻ cách tiếp cận của họ nếu họ thấy mã của tôi không tốt :)
public static boolean isKeyboardShown(Context context, View view) {
if (context == null || view == null) {
return false;
}
InputMethodManager imm = (InputMethodManager) context
.getSystemService(Context.INPUT_METHOD_SERVICE);
return imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
im. leatherSoftInputFromWindow trả về boolean.
Cảm ơn,
if (keyopen())
{
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY,0);
}
Chức năng trên là những gì tôi sử dụng để kiểm tra xem Bàn phím có hiển thị hay không. Nếu có, thì tôi đóng nó lại.
Dưới đây cho thấy hai phương pháp cần thiết.
Đầu tiên, xác định chiều cao cửa sổ có thể thực hiện được trong onCreate.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// add to onCreate method
Rect rectgle= new Rect();
Window window= getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
sheight= rectgle.bottom;
//
}
Sau đó, thêm một phương thức boolean lấy chiều cao Window tại trường hợp đó. Nếu nó không khớp với bản gốc (giả sử bạn không thay đổi nó trên đường đi ...) thì bàn phím đang mở.
public boolean keyopen()
{
Rect rectgle= new Rect();
Window window= getWindow();
window.getDecorView().getWindowVisibleDisplayFrame(rectgle);
int curheight= rectgle.bottom;
if (curheight!=sheight)
{
return true;
}
else
{
return false;
}
}
Frotz!
Tôi biết chính xác làm thế nào bạn có thể xác định nếu bàn phím bị ẩn hay không.
public int getStatusBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("status_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
public int getNavigationBarHeight() {
int result = 0;
int resourceId = getResources().getIdentifier("navigation_bar_height", "dimen", "android");
if (resourceId > 0) {
result = getResources().getDimensionPixelSize(resourceId);
}
return result;
}
public boolean isKeyboardHidden() {
int delta = mRootView.getRootView().getHeight() - mRootView.getHeight() - getNavigationBarHeight() - getStatusBarHeight()
- getSupportActionBar().getHeight();
return delta <= 0;
}
Điều này làm việc cho máy tính bảng. Khi thanh điều hướng được hiển thị theo chiều ngang.