Android:检测软键盘打开
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3081276/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android: Detect softkeyboard open
提问by Noah Seidman
When the soft keyboard opens I want a scroll view to scroll down to the bottom.
当软键盘打开时,我希望滚动视图向下滚动到底部。
For this I can use: fullScroll(View.FOCUS_DOWN);
为此,我可以使用: fullScroll(View.FOCUS_DOWN);
But how do I fire that command after the soft keyboard opening event triggers?
但是在软键盘打开事件触发后如何触发该命令?
采纳答案by Rich Schuler
Per this postand this poston android-developers it doesn't seem like it's possible to do what you want. You may want to re-examine your use case for what you're doing. Maybe one of the softInputMode
flags will work for you.
根据这篇文章和这篇关于 android-developers 的文章,似乎不可能做你想做的事。您可能想要重新检查您的用例以了解您正在做什么。也许其中一个softInputMode
标志对你有用。
回答by BoD
Here is my solution:
这是我的解决方案:
1/ A simple interface
1/ 一个简单的界面
public interface KeyboardVisibilityListener {
void onKeyboardVisibilityChanged(boolean keyboardVisible);
}
2/ A utility method (put it where you want, for instance in a class named KeyboardUtil
)
2/ 一个实用方法(把它放在你想要的地方,例如在一个名为 的类中KeyboardUtil
)
public static void setKeyboardVisibilityListener(Activity activity, KeyboardVisibilityListener keyboardVisibilityListener) {
View contentView = activity.findViewById(android.R.id.content);
contentView.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
private int mPreviousHeight;
@Override
public void onGlobalLayout() {
int newHeight = contentView.getHeight();
if (mPreviousHeight != 0) {
if (mPreviousHeight > newHeight) {
// Height decreased: keyboard was shown
keyboardVisibilityListener.onKeyboardVisibilityChanged(true);
} else if (mPreviousHeight < newHeight) {
// Height increased: keyboard was hidden
keyboardVisibilityListener.onKeyboardVisibilityChanged(false);
} else {
// No change
}
}
mPreviousHeight = newHeight;
}
});
}
3/ Use from an Activity this way (a good place is in onCreate):
3/ 以这种方式从活动中使用(一个好地方是在 onCreate 中):
KeyboardUtil.setKeyboardVisibilityListener(this, mKeyboardVisibilityListener);
回答by yeradis
watching the date , possibly you have a solution for your question, otherwise:
看日期,可能你有你的问题的解决方案,否则:
Here is the same response i made to another question related : Is there a way to tell if the soft-keyboard is shown?
这是我对另一个相关问题的相同回答:有没有办法判断软键盘是否显示?
but i copy full response here to avoid dead links:
但我在此处复制完整回复以避免死链接:
Please check Configuration Changesfor your Activity
请检查您的活动的配置更改
This for your AndroidManifest.xml
这适用于您的AndroidManifest.xml
and this for your Activityclass http://developer.android.com/reference/android/app/Activity.html#onConfigurationChanged(android.content.res.Configuration)
You will need to @Override the public method onConfigurationChanged(android.content.res.Configuration) of your Activity to be able to handle, for example, this values:
hardKeyboardHidden,
keyboard,
keyboardHidden
您需要@OverrideActivity的公共方法onConfigurationChanged(android.content.res.Configuration) 才能处理,例如,以下值:
hardKeyboardHidden、
keyboard、
keyboardHidden
For all possible values check http://developer.android.com/reference/android/content/res/Configuration.html
对于所有可能的值,请检查http://developer.android.com/reference/android/content/res/Configuration.html
You will see there something like this:
你会看到这样的事情:
HARDKEYBOARDHIDDEN_NO
HARDKEYBOARDHIDDEN_UNDEFINED
HARDKEYBOARDHIDDEN_YES
KEYBOARDHIDDEN_NO
KEYBOARDHIDDEN_UNDEFINED
KEYBOARDHIDDEN_YES
KEYBOARD_12KEY
KEYBOARD_NOKEYS
KEYBOARD_QWERTY
KEYBOARD_UNDEFINED
Also there you will be able to read something like this:
此外,您还可以阅读以下内容:
public int hardKeyboardHidden A flag indicating whether the hard keyboard has been hidden.
public int keyboard The kind of keyboard attached to the device.
public int keyboardHidden A flag indicating whether any keyboard is available.
UPDATE:
更新:
Here is a specific sampleof what i′m talking about:
这是我正在谈论的具体示例:
http://developer.android.com/guide/topics/resources/runtime-changes.html
http://developer.android.com/guide/topics/resources/runtime-changes.html
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Checks the orientation of the screen
if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
Toast.makeText(this, "landscape", Toast.LENGTH_SHORT).show();
} else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT){
Toast.makeText(this, "portrait", Toast.LENGTH_SHORT).show();
}
// Checks whether a hardware keyboard is available
if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO) {
Toast.makeText(this, "keyboard visible", Toast.LENGTH_SHORT).show();
} else if (newConfig.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
Toast.makeText(this, "keyboard hidden", Toast.LENGTH_SHORT).show();
}
}
I hope this help you
我希望这对你有帮助
回答by Roberto Andrade
The only way I was able to work around this is by setting my activity's android:windowSoftInputMode="adjustResize" and then embed a custom "detector view" in the layout to handle a container size change and propagate that as a custom event (via a Listener) for soft keyboard on/off.
我能够解决这个问题的唯一方法是设置我的活动的 android:windowSoftInputMode="adjustResize",然后在布局中嵌入一个自定义的“检测器视图”来处理容器大小的变化并将其作为自定义事件传播(通过侦听器)用于打开/关闭软键盘。
The following post describes an approach to implementing it: EditText does not trigger changes when back is pressed
下面的帖子描述了一种实现它的方法:EditText 在按下后退时不会触发更改
回答by Ramón Pérez Silva
This works for me
这对我有用
parent.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
@Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
boolean someHasFocus = false;
if(host.hasFocus())
someHasFocus = true;
if(folder.hasFocus())
someHasFocus = true;
if(user.hasFocus())
someHasFocus = true;
if(pass.hasFocus())
someHasFocus = true;
if(someHasFocus){
if(bottom>oldBottom){
// Keyboard Close
viewToHide.setVisibility(View.VISIBLE);
}else if(bottom<oldBottom){
// Keyboard Open
viewToHide.setVisibility(View.GONE);
}
}else{
// show
viewToHide.setVisibility(View.VISIBLE);
}
}
});
Where parent is the main layout, viewToHide is the view that shows or hides when the keyboard is shown, and host,folder,user and pass are the EditText of my form.
其中 parent 是主要布局,viewToHide 是在显示键盘时显示或隐藏的视图,host、folder、user 和 pass 是我的表单的 EditText。
And this in the manifest
这在清单中
android:windowSoftInputMode="stateHidden|adjustResize"
Hope this help
希望这有帮助
回答by Grimmy
Here is my solution. It doesn't need android:windowSoftInputMode="adjustResize"
这是我的解决方案。它不需要 android:windowSoftInputMode="adjustResize"
public abstract class KeyboardActivity extends Activity {
public static final int MIN_KEYBOARD_SIZE = 100;
private Window mRootWindow;
private View mRootView;
private int mKeyboardHeight = -1;
private ViewTreeObserver.OnGlobalLayoutListener mGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
public int height;
public void onGlobalLayout() {
Rect r = new Rect();
View view = mRootWindow.getDecorView();
view.getWindowVisibleDisplayFrame(r);
if (height != r.height()) {
int diff = height - r.height();
height = r.height();
if (Math.abs(diff) > MIN_KEYBOARD_SIZE) {
int diff = height - r.height();
if (height != 0 && Math.abs(diff) > MIN_KEYBOARD_SIZE) {
mKeyboardHeight = Math.abs(diff);
if (diff > 0) {
onKeyboardOpen();
} else {
onKeyboardClosed();
}
}
height = r.height();
}
}
};
protected abstract void onKeyboardClosed();
protected abstract void onKeyboardOpen();
/**
* Should return keyboard height, if keyboard was shown at least once;
* @return keyboard height or -1
*/
protected int getKeyboardHeight() {
return mKeyboardHeight;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mRootWindow = getWindow();
mRootView = mRootWindow.getDecorView().findViewById(android.R.id.content);
}
@Override
protected void onStart() {
super.onStart();
mRootView.getViewTreeObserver().addOnGlobalLayoutListener(mGlobalLayoutListener);
}
@Override
protected void onStop() {
super.onStop();
mRootView.getViewTreeObserver().removeOnGlobalLayoutListener(mGlobalLayoutListener);
}
}
Then I've just extend my activity from this activity and override onKeyboardClosed/onKeyboardOpen methods.
然后我只是从这个活动扩展我的活动并覆盖 onKeyboardClosed/onKeyboardOpen 方法。
回答by venkat
@BoD's answerworks fine if I remove the following line.
如果我删除以下行,@BoD 的答案就可以正常工作。
if (mPreviousHeight != 0) {
/* other code is same, because
mPreviousHeight is 0 when it comes first */
}
回答by John smith
for this what i used to do same:
为此,我曾经做过同样的事情:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.ViewGroup;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
public class SoftKeyboard implements View.OnFocusChangeListener
{
private static final int CLEAR_FOCUS = 0;
private ViewGroup layout;
private int layoutBottom;
private InputMethodManager im;
private int[] coords;
private boolean isKeyboardShow;
private SoftKeyboardChangesThread softKeyboardThread;
private List<EditText> editTextList;
private View tempView; // reference to a focused EditText
public SoftKeyboard(ViewGroup layout, InputMethodManager im)
{
this.layout = layout;
keyboardHideByDefault();
initEditTexts(layout);
this.im = im;
this.coords = new int[2];
this.isKeyboardShow = false;
this.softKeyboardThread = new SoftKeyboardChangesThread();
this.softKeyboardThread.start();
}
public void openSoftKeyboard()
{
if(!isKeyboardShow)
{
layoutBottom = getLayoutCoordinates();
im.toggleSoftInput(0, InputMethodManager.SHOW_IMPLICIT);
softKeyboardThread.keyboardOpened();
isKeyboardShow = true;
}
}
public void closeSoftKeyboard()
{
if(isKeyboardShow)
{
im.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0);
isKeyboardShow = false;
}
}
public void setSoftKeyboardCallback(SoftKeyboardChanged mCallback)
{
softKeyboardThread.setCallback(mCallback);
}
public void unRegisterSoftKeyboardCallback()
{
softKeyboardThread.stopThread();
}
public interface SoftKeyboardChanged
{
public void onSoftKeyboardHide();
public void onSoftKeyboardShow();
}
private int getLayoutCoordinates()
{
layout.getLocationOnScreen(coords);
return coords[1] + layout.getHeight();
}
private void keyboardHideByDefault()
{
layout.setFocusable(true);
layout.setFocusableInTouchMode(true);
}
/*
* InitEditTexts now handles EditTexts in nested views
* Thanks to Francesco Verheye ([email protected])
*/
private void initEditTexts(ViewGroup viewgroup)
{
if(editTextList == null)
editTextList = new ArrayList<EditText>();
int childCount = viewgroup.getChildCount();
for(int i=0; i<= childCount-1;i++)
{
View v = viewgroup.getChildAt(i);
if(v instanceof ViewGroup)
{
initEditTexts((ViewGroup) v);
}
if(v instanceof EditText)
{
EditText editText = (EditText) v;
editText.setOnFocusChangeListener(this);
editText.setCursorVisible(true);
editTextList.add(editText);
}
}
}
/*
* OnFocusChange does update tempView correctly now when keyboard is still shown
* Thanks to Israel Dominguez ([email protected])
*/
@Override
public void onFocusChange(View v, boolean hasFocus)
{
if(hasFocus)
{
tempView = v;
if(!isKeyboardShow)
{
layoutBottom = getLayoutCoordinates();
softKeyboardThread.keyboardOpened();
isKeyboardShow = true;
}
}
}
// This handler will clear focus of selected EditText
private final Handler mHandler = new Handler()
{
@Override
public void handleMessage(Message m)
{
switch(m.what)
{
case CLEAR_FOCUS:
if(tempView != null)
{
tempView.clearFocus();
tempView = null;
}
break;
}
}
};
private class SoftKeyboardChangesThread extends Thread
{
private AtomicBoolean started;
private SoftKeyboardChanged mCallback;
public SoftKeyboardChangesThread()
{
started = new AtomicBoolean(true);
}
public void setCallback(SoftKeyboardChanged mCallback)
{
this.mCallback = mCallback;
}
@Override
public void run()
{
while(started.get())
{
// Wait until keyboard is requested to open
synchronized(this)
{
try
{
wait();
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
int currentBottomLocation = getLayoutCoordinates();
// There is some lag between open soft-keyboard function and when it really appears.
while(currentBottomLocation == layoutBottom && started.get())
{
currentBottomLocation = getLayoutCoordinates();
}
if(started.get())
mCallback.onSoftKeyboardShow();
// When keyboard is opened from EditText, initial bottom location is greater than layoutBottom
// and at some moment equals layoutBottom.
// That broke the previous logic, so I added this new loop to handle this.
while(currentBottomLocation >= layoutBottom && started.get())
{
currentBottomLocation = getLayoutCoordinates();
}
// Now Keyboard is shown, keep checking layout dimensions until keyboard is gone
while(currentBottomLocation != layoutBottom && started.get())
{
synchronized(this)
{
try
{
wait(500);
} catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
currentBottomLocation = getLayoutCoordinates();
}
if(started.get())
mCallback.onSoftKeyboardHide();
// if keyboard has been opened clicking and EditText.
if(isKeyboardShow && started.get())
isKeyboardShow = false;
// if an EditText is focused, remove its focus (on UI thread)
if(started.get())
mHandler.obtainMessage(CLEAR_FOCUS).sendToTarget();
}
}
public void keyboardOpened()
{
synchronized(this)
{
notify();
}
}
public void stopThread()
{
synchronized(this)
{
started.set(false);
notify();
}
}
}
}
and in your Activity
or fragment
call this method in onCreate()
并在您的Activity
或fragment
调用此方法中onCreate()
private void hideAndShowKeyBOrd() {
InputMethodManager im = (InputMethodManager) getActivity().getSystemService(Service.INPUT_METHOD_SERVICE);
/*
Instantiate and pass a callback
*/
SoftKeyboard softKeyboard;
softKeyboard = new SoftKeyboard(mainLayout, im);
softKeyboard.setSoftKeyboardCallback(new SoftKeyboard.SoftKeyboardChanged() {
@Override
public void onSoftKeyboardHide() {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
}
});
}
@Override
public void onSoftKeyboardShow() {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
if (viewV.getVisibility() == View.VISIBLE) {
viewV.setVisibility(View.GONE);
}
}
});
}
});
}
enjoy your code:)
享受你的代码:)