当软键盘打开时,我希望滚动视图自动向下滚动到底部。
为了实现这个目的,我们可以使用以下代码:fullScroll(View.FOCUS_DOWN);
但是,如何在软键盘打开事件触发后执行该命令呢?
这是我的解决方案:
1/ 一个简单的界面
public interface KeyboardVisibilityListener {
void onKeyboardVisibilityChanged(boolean keyboardVisible);
}
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/ 可以在 Activity 中这样使用(onCreate 是一个很好的位置):
KeyboardUtil.setKeyboardVisibilityListener(this, mKeyboardVisibilityListener);
android:inputType="textPassword"
失败了,但还是有一个不错的方法! - User3观察日期,可能你已经有了解决方案,否则:
这里是我对另一个相关问题的回答:有办法判断软键盘是否显示?
但为了避免死链接,我在此处复制完整回答:
请检查您的Activity的配置更改
这是您的AndroidManifest.xml
以及您的Activity类 http://developer.android.com/reference/android/app/Activity.html#onConfigurationChanged(android.content.res.Configuration)
您需要@覆盖您的Activity的公共方法onConfigurationChanged(android.content.res.Configuration)来处理例如以下值:
查看所有可能的值,请访问http://developer.android.com/reference/android/content/res/Configuration.html。
你将会看到类似于这样的内容:
HARDKEYBOARDHIDDEN_NO
HARDKEYBOARDHIDDEN_UNDEFINED
HARDKEYBOARDHIDDEN_YES
KEYBOARDHIDDEN_NO
KEYBOARDHIDDEN_UNDEFINED
KEYBOARDHIDDEN_YES
KEYBOARD_12KEY
KEYBOARD_NOKEYS
KEYBOARD_QWERTY
KEYBOARD_UNDEFINED
同时,您还可以在那里阅读类似于以下内容的信息:
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.
更新:
这是一个具体的示例,以说明我的意思:
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();
}
}
我希望这能帮到你
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);
}
}
});
其中parent是主要布局,viewToHide是在键盘显示或隐藏时显示或隐藏的视图,host、folder、user和pass是我的表单中的EditText。
而这是在清单文件中的内容。
android:windowSoftInputMode="stateHidden|adjustResize"
对于这个,我以前做的是一样的:
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 (verheye.francesco@gmail.com)
*/
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 (dominguez.israel@gmail.com)
*/
@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();
}
}
}
}
在你的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);
}
}
});
}
});
}
享受你的代码:)
android.support.design.widget.TextInputLayout
。 - User3在运行组合测试时,这对我起作用了
fun isKeyboardOpenedShellCheck(): Boolean {
val checkKeyboardCmd = "dumpsys input_method | grep mInputShown"
try {
return UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
.executeShellCommand(checkKeyboardCmd).contains("mInputShown=true")
} catch (e: IOException) {
throw RuntimeException("Keyboard check failed", e)
}
}
这是可行的解决方案!
fun Activity.isKeyboardClosed(): Boolean {
return !this.isKeyboardOpen()
}
private fun Activity.isKeyboardOpen(): Boolean {
val visibleBounds = Rect()
this.getRootView().getWindowVisibleDisplayFrame(visibleBounds)
val heightDiff = getRootView().height - visibleBounds.height()
val marginOfError = this.convertDpToPx(50F).roundToInt()
return heightDiff > marginOfError
}
private fun Activity.getRootView(): View {
return findViewById<View>(android.R.id.content)
}
private fun Context.convertDpToPx(dp: Float): Float {
return TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
dp,
this.resources.displayMetrics
)
}
这是我的解决方案。它不需要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);
}
}
接着我只需从这个活动中扩展我的活动并覆盖onKeyboardClosed/onKeyboardOpen方法。
如果我删除以下行,@BoD's answer 就可以正常工作。
if (mPreviousHeight != 0) {
/* other code is same, because
mPreviousHeight is 0 when it comes first */
}