前言
最近做需求,遇到软键盘弹起底部布局按钮被顶起的情况,需求不一样,对应方法也会存在差异性,说说我遇到的问题及解决过程。
问题
登录页根布局是RelativeLayout,底部有一个登录按钮通过android:layout_alignParentBottom="true"放至最底部,软键盘弹起时按钮会被顶到键盘上,遮住输入框,体验巨差。
修改
1.在manifest里面加入键盘属性android:windowSoftInputMode="adjustPan”,关于它的参数
详情可以看看这篇文章https://www.jianshu.com/p/e59a0b49cdc1。虽然对我没什么用,不过还是记录下,万一对其他人有用呢。
2.布局里面加入Scrollerview,将要显示在软键盘之上的布局包裹起来,这样软键盘会一直在要显示的布局下方,但底部按钮不会跟着上移。亲测在部分机型上有用,但是有个华为手机任然无效。
3.无奈只能监听软键盘的弹起跟收入了,我是这么操作的,上代码
/**
* 监听键盘弹起,防止键盘顶起底部布局
*/
private void setLayoutKayBoard() {
//根布局
RelativeLayout rootView = (RelativeLayout) findViewById(R.id.rl_rootview);
rootView.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) {
/*有的是根据if (bottom - oldBottom < -1) 跟(bottom - oldBottom > 1)来判断软键盘是否弹起的,
但我实际打印出来两个值相等,所以并不能解决我的问题,于是我用了以下方式*/
boolean softInputVisible = KeyboardUtils.isSoftInputVisible(LoginActivity.this);
if (softInputVisible) {
//Todo这个地方可以根据自己具体的业务需求进行相应的操作,我比较粗暴,直接隐藏了
mTvLogin.setVisibility(View.GONE);
} else {
//这里延时是为了交互效果,可以根据自己的情况自行修改
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
mTvLogin.setVisibility(View.VISIBLE);
}
},10);
}
}
});
}
我这里用到了一个软键盘工具类KeyboardUtils:
public final class KeyboardUtils {
private static int sContentViewInvisibleHeightPre;
private static OnGlobalLayoutListener onGlobalLayoutListener;
private static OnSoftInputChangedListener onSoftInputChangedListener;
private KeyboardUtils() {
throw new UnsupportedOperationException("u can't instantiate me...");
}
/**
* Show the soft input.
*
* @param activity The activity.
*/
public static void showSoftInput(final Activity activity) {
InputMethodManager imm =
(InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
if (imm == null) return;
View view = activity.getCurrentFocus();
if (view == null) {
view = new View(activity);
view.setFocusable(true);
view.setFocusableInTouchMode(true);
view.requestFocus();
}
imm.showSoftInput(view, InputMethodManager.SHOW_FORCED);
}
/**
* Show the soft input.
*
* @param view The view.
*/
public static void showSoftInput(final View view) {
InputMethodManager imm =
(InputMethodManager) Utils.getApp().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm == null) return;
view.setFocusable(true);
view.setFocusableInTouchMode(true);
view.requestFocus();
imm.showSoftInput(view, InputMethodManager.SHOW_FORCED);
}
/**
* Hide the soft input.
*
* @param activity The activity.
*/
public static void hideSoftInput(final Activity activity) {
InputMethodManager imm =
(InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
if (imm == null) return;
View view = activity.getCurrentFocus();
if (view == null) view = new View(activity);
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
/**
* Hide the soft input.
*
* @param view The view.
*/
public static void hideSoftInput(final View view) {
InputMethodManager imm =
(InputMethodManager) Utils.getApp().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm == null) return;
imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
}
/**
* Toggle the soft input display or not.
*/
public static void toggleSoftInput() {
InputMethodManager imm =
(InputMethodManager) Utils.getApp().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm == null) return;
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, 0);
}
/**
* Return whether soft input is visible.
* <p>The minimum height is 200</p>
*
* @param activity The activity.
* @return {@code true}: yes<br>{@code false}: no
*/
public static boolean isSoftInputVisible(final Activity activity) {
return isSoftInputVisible(activity, 200);
}
/**
* Return whether soft input is visible.
*
* @param activity The activity.
* @param minHeightOfSoftInput The minimum height of soft input.
* @return {@code true}: yes<br>{@code false}: no
*/
public static boolean isSoftInputVisible(final Activity activity,
final int minHeightOfSoftInput) {
return getContentViewInvisibleHeight(activity) >= minHeightOfSoftInput;
}
private static int getContentViewInvisibleHeight(final Activity activity) {
final View contentView = activity.findViewById(android.R.id.content);
final Rect outRect = new Rect();
contentView.getWindowVisibleDisplayFrame(outRect);
LogUtils.d(contentView.getTop(), contentView.getBottom(), outRect.top, outRect.bottom);
return contentView.getBottom() - outRect.bottom;
}
/**
* Register soft input changed listener.
*
* @param activity The activity.
* @param listener The soft input changed listener.
*/
public static void registerSoftInputChangedListener(final Activity activity,
final OnSoftInputChangedListener listener) {
final int flags = activity.getWindow().getAttributes().flags;
if ((flags & WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS) != 0) {
activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
}
final View contentView = activity.findViewById(android.R.id.content);
sContentViewInvisibleHeightPre = getContentViewInvisibleHeight(activity);
onSoftInputChangedListener = listener;
onGlobalLayoutListener = new OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (onSoftInputChangedListener != null) {
int height = getContentViewInvisibleHeight(activity);
if (sContentViewInvisibleHeightPre != height) {
onSoftInputChangedListener.onSoftInputChanged(height);
sContentViewInvisibleHeightPre = height;
}
}
}
};
contentView.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener);
}
/**
* Register soft input changed listener.
*
* @param activity The activity.
*/
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
public static void unregisterSoftInputChangedListener(final Activity activity) {
final View contentView = activity.findViewById(android.R.id.content);
contentView.getViewTreeObserver().removeOnGlobalLayoutListener(onGlobalLayoutListener);
onSoftInputChangedListener = null;
onGlobalLayoutListener = null;
}
/**
* Fix the leaks of soft input.
* <p>Call the function in {@link Activity#onDestroy()}.</p>
*
* @param context The context.
*/
public static void fixSoftInputLeaks(final Context context) {
if (context == null) return;
InputMethodManager imm =
(InputMethodManager) Utils.getApp().getSystemService(Context.INPUT_METHOD_SERVICE);
if (imm == null) return;
String[] strArr = new String[]{"mCurRootView", "mServedView", "mNextServedView"};
for (int i = 0; i < 3; i++) {
try {
Field declaredField = imm.getClass().getDeclaredField(strArr[i]);
if (declaredField == null) continue;
if (!declaredField.isAccessible()) {
declaredField.setAccessible(true);
}
Object obj = declaredField.get(imm);
if (obj == null || !(obj instanceof View)) continue;
View view = (View) obj;
if (view.getContext() == context) {
declaredField.set(imm, null);
} else {
return;
}
} catch (Throwable th) {
th.printStackTrace();
}
}
}
/**
* Click blankj area to hide soft input.
* <p>Copy the following code in ur activity.</p>
*/
public static void clickBlankArea2HideSoftInput() {
Log.i("KeyboardUtils", "Please refer to the following code.");
/*
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
View v = getCurrentFocus();
if (isShouldHideKeyboard(v, ev)) {
InputMethodManager imm =
(InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(v.getWindowToken(),
InputMethodManager.HIDE_NOT_ALWAYS
);
}
}
return super.dispatchTouchEvent(ev);
}
// Return whether touch the view.
private boolean isShouldHideKeyboard(View v, MotionEvent event) {
if (v != null && (v instanceof EditText)) {
int[] l = {0, 0};
v.getLocationInWindow(l);
int left = l[0],
top = l[1],
bottom = top + v.getHeight(),
right = left + v.getWidth();
return !(event.getX() > left && event.getX() < right
&& event.getY() > top && event.getY() < bottom);
}
return false;
}
*/
}
public interface OnSoftInputChangedListener {
void onSoftInputChanged(int height);
}
}
记录一下为了防止下次遇到又忘记或者查询半天无果浪费时间。
在Android开发中,遇到软键盘弹起导致底部布局按钮被遮挡的问题。通过尝试设置`android:windowSoftInputMode="adjustPan"`、使用ScrollView以及监听键盘状态,最终采用键盘监听的方法解决了华为手机上底部布局不随键盘移动的问题。涉及到的工具类为KeyboardUtils。
3905

被折叠的 条评论
为什么被折叠?



