史上最全:安卓监听软键盘打开或者关闭
SoftKeyboard open and close listener in an activity in Android?
问题:我有一个Activity,里面有5个EditText。当用户点击第一个EditText,软键盘打来,然后可以输入一些值。我翔在软件版打开的时候,设置其他View的不可见,当软键盘关闭的时候其他View课件。
说白了就是对软键盘的事件进行更新。
到底安卓立有没有类似的listener或者callback甚至是一些技巧呢?
我总结了一下一共有3中方法,期中又简单也有复杂的。
方法1
对于某些场景,可以使用一些比较丑陋的代码,但也可以算是黑科技。
可能为你的EditText**设置焦点监听**就足够了
yourEditText.setOnFocusChangeListener(new OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus) {
//got focus
} else {
//lost focus
}
}
});
方法2
下面的方法只有在你的清单文件中,把Activity的android:windowSoftInputMode
属性设置为adjustResize
才有用。你可以使用Layout listener去观察你的根布局的大小是否改变。
首先你要创建一个BaseAvtivity
public class BaseActivity extends Activity {
private ViewTreeObserver.OnGlobalLayoutListener keyboardLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int heightDiff = rootLayout.getRootView().getHeight() - rootLayout.getHeight();
int contentViewTop = getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop();
LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(BaseActivity.this);
if(heightDiff <= contentViewTop){
onHideKeyboard();
Intent intent = new Intent("KeyboardWillHide");
broadcastManager.sendBroadcast(intent);
} else {
int keyboardHeight = heightDiff - contentViewTop;
onShowKeyboard(keyboardHeight);
Intent intent = new Intent("KeyboardWillShow");
intent.putExtra("KeyboardHeight", keyboardHeight);
broadcastManager.sendBroadcast(intent);
}
}
};
private boolean keyboardListenersAttached = false;
private ViewGroup rootLayout;
protected void onShowKeyboard(int keyboardHeight) {}
protected void onHideKeyboard() {}
protected void attachKeyboardListeners() {
if (keyboardListenersAttached) {
return;
}
rootLayout = (ViewGroup) findViewById(R.id.rootLayout);
rootLayout.getViewTreeObserver().addOnGlobalLayoutListener(keyboardLayoutListener);
keyboardListenersAttached = true;
}
@Override
protected void onDestroy() {
super.onDestroy();
if (keyboardListenersAttached) {
rootLayout.getViewTreeObserver().removeGlobalOnLayoutListener(keyboardLayoutListener);
}
}
}
让你的Activity继承BaseActivity
public class TestActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_activity);
attachKeyboardListeners();
}
@Override
protected void onShowKeyboard(int keyboardHeight) {
// do things when keyboard is shown
bottomContainer.setVisibility(View.GONE);
}
@Override
protected void onHideKeyboard() {
// do things when keyboard is hidden
bottomContainer.setVisibility(View.VISIBLE);
}
}
方法3
Android给你提供的大量的api,这些api提供的大量可以重写的方法,这些方法涵盖了你可能遇到的大量的时间。所以说大部分时间你都不用去担心。但soft ketyboard并不是这样。它可以轻松的展示或者隐藏,但没有方法去监听它。下面是一个解决方案。
创建一个SoftKeyboard
类
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 处理嵌套在view里的edittext
* 感谢 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);
}
}
}
/*
* 当keyboard展示的时候,OnFocusChange 更新 tempView
* 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;
}
}
}
// 将会取消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())
{
// 等待,知道软键盘请求打卡
synchronized(this)
{
try
{
wait();
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
int currentBottomLocation = getLayoutCoordinates();
// 在调用打开软键盘函数和真正显示,有一些时间差
while(currentBottomLocation == layoutBottom && started.get())
{
currentBottomLocation = getLayoutCoordinates();
}
if(started.get())
mCallback.onSoftKeyboardShow();
// 当键盘打开,出事下底部的位置比layoutBottom更好
// 在有些情况下等价于layoutBottom
// 这会破坏之前的逻辑,所以我加上新的循环
while(currentBottomLocation >= layoutBottom && started.get())
{
currentBottomLocation = getLayoutCoordinates();
}
// 现在键盘已经显示,继续检查Layout的尺寸,直到键盘关闭
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();
// 如果 keyboard 已经打开
if(isKeyboardShow && started.get())
isKeyboardShow = false;
// 如果一个EditText获得焦点,移除它焦点(在UI县城中)
if(started.get())
mHandler.obtainMessage(CLEAR_FOCUS).sendToTarget();
}
}
public void keyboardOpened()
{
synchronized(this)
{
notify();
}
}
public void stopThread()
{
synchronized(this)
{
started.set(false);
notify();
}
}
}
}
下面是简单的一个例子
RelativeLayout mainLayout = findViewById(R.layout.main_layout); // You must use the layout root
InputMethodManager im = (InputMethodManager) 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()
{
// Code here
}
@Override
public void onSoftKeyboardShow()
{
// Code here
}
});
/*
Open or close the soft keyboard easily
*/
softKeyboard.openSoftKeyboard();
softKeyboard.closeSoftKeyboard();
/* Prevent memory leaks:
*/
@Override
public void onDestroy()
{
super.onDestroy();
softKeyboard.unRegisterSoftKeyboardCallback();
}
希望对你有帮助
参考自stackoverflow,以及felhr