我需要做一件非常简单的事情——找出软键盘是否显示。这在安卓系统中可行吗?
我需要做一件非常简单的事情——找出软键盘是否显示。这在安卓系统中可行吗?
因为:
因此,猜测IME总是错误的 - 不要猜测,要确保!!!
@kevin-du目前是最好的解决方案,因为它查询IMM以获取IME高度 - 但正如所说的那样,该方法是隐藏的API,因此使用它可能会导致错误的“假阴性结果” - 因为错误的开发者使用。
Reuben Scratton的新答案(计算HeightDiff int heightDiff = activityRootView.getRootView().getHeight() - activityRootView.getHeight();
)在设置半透明状态栏模式的活动中将无法工作。
如果您使用半透明状态栏,activityRootView.getHeight()
将永远不会改变,无论软键盘是否可见。它将始终返回活动和状态栏的高度。
例如,Nexus 4,Android 5.0.1,将android:windowTranslucentStatus
设置为true,它将永远返回1184,即使ime已打开。如果将android:windowTranslucentStatus
设置为false,则会正确返回高度,如果ime不可见,则返回1134(不包括状态栏)。关闭ime,它可能会返回5xx(取决于ime的高度)
我不知道这是否是一个错误,我已经尝试了4.4.4和5.0.1,结果是相同的。
因此,到目前为止,第二个最受欢迎的答案,Kachi的解决方案将是计算ime高度最安全的方法。以下是复制:
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
}
}
});
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 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;
}
这适用于平板电脑。当导航栏水平显示时。
这里有一个解决方法,可以知道软键盘是否可见。
一些流行的键盘在其 classNames 中具有某些关键字:
Google AOSP = IME
Swype = IME
Swiftkey = KeyboardService
Fleksy = keyboard
Adaptxt = IME (KPTAdaptxtIME)
Smart = Keyboard (SmartKeyboard)
View#setOnApplyWindowInsetsListener 可以用于获取窗口插图回调
public void setOnApplyWindowInsetsListener(OnApplyWindowInsetsListener listener) {
getListenerInfo().mOnApplyWindowInsetsListener = listener;
}
//OnApplyWindowInsetsListener
public WindowInsets onApplyWindowInsets(View v, WindowInsets insets);
boolean keyboardVisible = insets.isVisible(WindowInsets.Type.ime())
可以确定键盘的可见状态。
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
所以对于片段,整个代码应该是
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = super.onCreateView(inflater, container, savedInstanceState);
//mWebView.postUrl("https://www.google.com/");
final View activityRootView = view;
layoutListener = 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);
// This variable was created only for Debug purposes and
// to see the height change when clicking on a field inside mWebView
int screenHeight = activityRootView.getRootView().getHeight();
Log.d("onGlobalLayout", "rect: " + r.toString());
Log.d("onGlobalLayout", "screenHeight: " + screenHeight);
//The difference on the heights from bottom to top and on the root height
int heightDiff = screenHeight - (r.bottom - r.top);
Log.d("onGlobalLayout", "heightDiff: " + heightDiff);
//I suggest to put 250 on resources to have better order
float dpx = dpToPx(getActivity(), 250);
if (previousHeightDiff != heightDiff) {
if (heightDiff > dpx) {
isSoftKeyboardPresent = true;
} else {
isSoftKeyboardPresent = false;
}
previousHeightDiff = heightDiff;
}
}
};
activityRootView.getViewTreeObserver().addOnGlobalLayoutListener(layoutListener);
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
return view;
}
private static float dpToPx(Context context, float valueInDp) {
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, valueInDp, metrics);
}
这可能不适合生产环境,因为它会打开键盘。请注意,类似函数返回的布尔值在API中没有指定,因此不可靠。请参阅此处的文档...
public boolean showSoftInput (View view,
int flags,
ResultReceiver resultReceiver)
这段代码运行良好
使用此类作为根视图:
public class KeyboardConstraintLayout extends ConstraintLayout {
private KeyboardListener keyboardListener;
private EditText targetEditText;
private int minKeyboardHeight;
private boolean isShow;
public KeyboardConstraintLayout(Context context) {
super(context);
minKeyboardHeight = getResources().getDimensionPixelSize(R.dimen.keyboard_min_height);
}
public KeyboardConstraintLayout(Context context, AttributeSet attrs) {
super(context, attrs);
minKeyboardHeight = getResources().getDimensionPixelSize(R.dimen.keyboard_min_height);
}
public KeyboardConstraintLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
minKeyboardHeight = getResources().getDimensionPixelSize(R.dimen.keyboard_min_height);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (!isInEditMode()) {
Activity activity = (Activity) getContext();
@SuppressLint("DrawAllocation")
Rect rect = new Rect();
getWindowVisibleDisplayFrame(rect);
int statusBarHeight = rect.top;
int keyboardHeight = activity.getWindowManager().getDefaultDisplay().getHeight() - (rect.bottom - rect.top) - statusBarHeight;
if (keyboardListener != null && targetEditText != null && targetEditText.isFocused()) {
if (keyboardHeight > minKeyboardHeight) {
if (!isShow) {
isShow = true;
keyboardListener.onKeyboardVisibility(true);
}
}else {
if (isShow) {
isShow = false;
keyboardListener.onKeyboardVisibility(false);
}
}
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public boolean isShowKeyboard() {
return isShow;
}
public void setKeyboardListener(EditText targetEditText, KeyboardListener keyboardListener) {
this.targetEditText = targetEditText;
this.keyboardListener = keyboardListener;
}
public interface KeyboardListener {
void onKeyboardVisibility (boolean isVisible);
}
}
并在活动或片段中设置键盘监听器:
rootLayout.setKeyboardListener(targetEditText, new KeyboardConstraintLayout.KeyboardListener() {
@Override
public void onKeyboardVisibility(boolean isVisible) {
}
});
一种不需要LayoutListener的方法
在我的情况下,我想在替换Fragment之前保存键盘的状态。我从onSaveInstanceState
调用hideSoftInputFromWindow方法,它关闭键盘并返回键盘是否可见。
这个方法很简单,但可能会改变你的键盘状态。