我需要做一件非常简单的事情-找出软件键盘是否显示。这在Android中可行吗?
当前回答
在了解了不同分辨率的一些问题后,我决定使用相对大小。正如我所注意到的,可见状态和隐藏状态之间的差异约为30%。所以我决定用0.3代替128 PX。
我添加了这个类监听器来通知任何变化。
这是我的版本
import android.app.*;
import android.graphics.*;
import android.view.*;
public class SoftKeyboardState {
public static final int HIDDEN = 0, VISIBLE = 1;
private OnKeyboardStateChangedListener listener;
private View decorView;
public SoftKeyboardState(Activity activity) {
this.decorView = activity.findViewById(android.R.id.content);
initKeyboardListener();
}
private void initKeyboardListener() {
decorView.getViewTreeObserver().addOnGlobalLayoutListener(
new ViewTreeObserver.OnGlobalLayoutListener(){
private final Rect windowVisibleDisplayFrame = new Rect();
private int lastVisibleDecorViewHeight;
@Override
public void onGlobalLayout() {
decorView.getWindowVisibleDisplayFrame(windowVisibleDisplayFrame);
final int visibleDecorViewHeight = windowVisibleDisplayFrame.height();
if (lastVisibleDecorViewHeight != 0) {
if ((lastVisibleDecorViewHeight > visibleDecorViewHeight) && (lastVisibleDecorViewHeight / visibleDecorViewHeight >= 0.3f)) {
// visible
if (listener != null)listener.onKeyboardStateChanged(VISIBLE);
} else if ((lastVisibleDecorViewHeight < visibleDecorViewHeight) && (visibleDecorViewHeight / lastVisibleDecorViewHeight >= 0.3f)) {
// hidden
if (listener != null)listener.onKeyboardStateChanged(HIDDEN);
}
}
lastVisibleDecorViewHeight = visibleDecorViewHeight;
}
});
}
public void setOnKeyboardStateChangedListener(OnKeyboardStateChangedListener listener) {
this.listener = listener;
}
public interface OnKeyboardStateChangedListener {
public void onKeyboardStateChanged(int state);
}
}
其他回答
抱歉回答晚了,但我已经创建了一个小的帮助类来处理打开/关闭事件,通知侦听器和其他有用的东西,可能有人会发现它有帮助:
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();
}
}
}
}
使用的例子:
final SoftKeyboardStateWatcher softKeyboardStateWatcher
= new SoftKeyboardStateWatcher(findViewById(R.id.activity_main_layout);
// Add listener
softKeyboardStateWatcher.addSoftKeyboardStateListener(...);
// then just handle callbacks
我的答案基本上与Kachi的答案相同,但我将它包装到一个很好的helper类中,以清理它在整个应用程序中的使用方式。
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);
}
}
你可以使用它来检测整个应用程序中的键盘变化,如下所示:
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
}
}
});
注意:只使用一个“寄存器”调用。它们都是一样的,只是为了方便
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
}
}
}
});
}
除了正确的答案,我必须在onCreateView的末尾添加这个,当使用一个片段内的webview。
getActivity().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
可能是因为我在一个片段中运行Webview,或者可能是API 30上的一个新行为,我的问题是,即使显示键盘,片段的高度也从未改变。
所以对于Fragment,整个代码应该是
@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);
}
这段代码工作得很好
根视图使用这个类:
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);
}
}
在activity或fragment中设置键盘监听器:
rootLayout.setKeyboardListener(targetEditText, new KeyboardConstraintLayout.KeyboardListener() {
@Override
public void onKeyboardVisibility(boolean isVisible) {
}
});
推荐文章
- 警告:API ' variable . getjavacompile()'已过时,已被' variable . getjavacompileprovider()'取代
- 安装APK时出现错误
- 碎片中的onCreateOptionsMenu
- TextView粗体通过XML文件?
- 如何使线性布局的孩子之间的空间?
- DSL元素android.dataBinding。enabled'已过时,已被'android.buildFeatures.dataBinding'取代
- ConstraintLayout:以编程方式更改约束
- PANIC: AVD系统路径损坏。检查ANDROID_SDK_ROOT值
- 如何生成字符串类型的buildConfigField
- Recyclerview不调用onCreateViewHolder
- Android API 21工具栏填充
- Android L中不支持操作栏导航模式
- 如何在TextView中添加一个子弹符号?
- PreferenceManager getDefaultSharedPreferences在Android Q中已弃用
- 在Android Studio中创建aar文件