我需要做一件非常简单的事情-找出软件键盘是否显示。这在Android中可行吗?
当前回答
而不是假设差异编码,我做了这样的事情,因为我在我的应用程序中有菜单选项。
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
}
}
});
其他回答
Reuben Scratton和Kachi提供的解决方案似乎依赖于设备的像素密度,如果你有一个高密度的设备,即使按下键盘,高度差也可能超过100。围绕这一点的工作将是看到初始高度差(键盘向下),然后与当前的差异进行比较。
boolean isOpened = false;
int firstHeightDiff = -1;
public void setListenerToRootView(){
final View activityRootView = getActivity().getWindow().getDecorView().findViewById(android.R.id.content);
Rect r = new Rect();
activityRootView.getWindowVisibleDisplayFrame(r);
firstHeightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (isAdded()) {
Rect r = new Rect();
activityRootView.getWindowVisibleDisplayFrame(r);
int heightDiff = activityRootView.getRootView().getHeight() - (r.bottom - r.top);
isOpened = heightDiff>firstHeightDiff+100;
if (isAdded())
if(isOpened) {
//TODO stuff for when it is up
} else {
//TODO stuf for when it is down
}
}
}
});
}
就计算机而言,这是永远的问题,但这个问题仍然令人难以置信地相关! 所以我把上面的答案结合起来,做了一些改进……
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);
}
});
}
这对我很管用。
就计算机而言,这是永远的问题,但这个问题仍然令人难以置信地相关!
所以我把上面的答案结合起来,做了一些改进……
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);
}
});
}
对我有用:)
注意: 如果你注意到DefaultKeyboardDP不适合你的设备播放的值,并发表评论,让每个人都知道应该是什么值…最终我们将得到适合所有设备的正确值!
要了解更多细节,请查看Cyborg上的实现
我认为这个方法将帮助你找出是键盘是可见的或不。
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;
}
}
2012年1月25日新增答案
写了下面的答案后,有人告诉我ViewTreeObserver和其他api的存在,这些api从版本1开始就潜伏在SDK中。
而不是需要一个自定义的布局类型,一个更简单的解决方案是给你的活动的根视图一个已知的ID,比如@+ ID /activityRoot,钩子一个GlobalLayoutListener到ViewTreeObserver,并从那里计算你的活动的视图根和窗口大小之间的大小差:
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
}
}
});
使用一个实用程序,如:
public static float dpToPx(Context context, float valueInDp) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, valueInDp, metrics);
}
简单!
注意: 你的应用程序必须在Android Manifest中设置这个标志Android:windowSoftInputMode=" adjuststresize "否则上述解决方案将无法工作。
原来的答案
是的,这是可能的,但它比应该的要难得多。
如果我需要关心键盘何时出现和消失(这是相当经常的),那么我所做的是自定义我的顶级布局类为一个覆盖onMeasure()。基本逻辑是,如果布局发现自己填充的面积明显小于窗口的总面积,那么可能显示了软键盘。
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);
}
}
然后在活动课上…
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
}
...
}
推荐文章
- 如何在新的材质主题中改变背面箭头的颜色?
- androidviewpager与底部点
- 相同的导航抽屉在不同的活动
- 如何从视图中获得托管活动?
- 单一的TextView与多种颜色的文本
- 如何在非活动类(LocationManager)中使用getSystemService ?
- 在清单中注册应用程序类?
- Android:从数组中编程创建旋转器
- Android命令行工具sdkmanager总是显示:警告:无法创建设置
- 如何设置RecyclerView应用程序:layoutManager=""从XML?
- 在没有开发服务器的情况下在设备上构建和安装unsigned apk ?
- 操作栏和新引入的工具栏有什么不同?
- 调整浮动动作按钮图标大小(fab)
- Android Studio无法找到有效的Jvm(与MAC OS相关)
- android:在触摸移动时移动视图