Android软键盘遮挡问题解决
2016-11-27 16:24
447 查看
在开发登录界面时,在点击某个EditText准备输入时,弹出的软键盘遮挡了按钮或者下面的输入框,在完成这个文本框的输入后,想要继续下面的操作,需要先隐藏软键盘。这会影响用户操作的流畅感,所以需要解决。在尝试了网上的几种处理方法后,最终选择了一种比较满意的方式。
这个图中有四个场景:
第一个场景,是没有弹出软键盘的登录界面,可以看出所有view都正常展示出来了;
第二个场景,弹出了软键盘,此时,下面的密码输入框、登录按钮都被遮挡了;
第三个场景,弹出了软键盘,输入了一个字母,此时,软键盘又增长了一部分,但是用户名输入框也上移了,并没有被遮盖。不同的手机的软键盘不同,我是在华为手机上遇到这种情况,在解决遮挡问题时也要考虑这个场景;
第四个场景,是我们的目标,弹出了软键盘,原来的视图整体上移了,显示出来我们要操作的view。
实测问题:
1,监听到onTouch动作后,进行滚动整个视图操作,需要延时才有效。
原因:onTouch时,软键盘还没有弹出,此时滚动到底部与不滚动是一样的效果。需要等软键盘弹出后,界面中的内容超过了一屏幕,此时的滚动才有效。
2,这个延时时间是多少?
不同手机的延时时间不一致,好的手机100ms就可以了,慢的手机延时500ms也不一定每次都有效果。
3,延时带来的问题:
若延时超过300ms,人眼就能感觉出来了:先是软键盘弹出,然后才是视图滚动。用户会感觉有些奇怪:为什么要动作两次呢?
这种方案,可以凑合使用了,可是,我们要做优雅的开发者,继续寻找!
这里,可以使用OnGlobalLayoutListener来实现。我们来学习下:
OnGlobalLayoutListener 是ViewTreeObserver的内部类,当一个视图树的布局发生改变时,可以被ViewTreeObserver监听到,这是一个注册监听视图树的观察者(observer),在视图树的全局事件改变时得到通知。
总结为简单一句话:使用OnGlobalLayoutListener可以监听到布局的变化。
监听到布局变化后,我们就可以自由的操作了:
可以外包一个ScrollView来进行滚动,使用一个
来滚动到底部。
不过,不使用ScrollView也能进行滚动的,例如LinearLayout也是可以滚动的,你还不知道吧,其实,我也是才知道:最基础的View就有个ScrollTo()函数的。
好了,基础知识准备好了,剩下就是滚动的距离计算了,我们这样来计算:
通过窗体的根View求出总的区域和可视区域,这样就可以计算出被遮挡的区域的高度,如果超过一定的值就判断为软键盘弹出了,然后将根View ScrollTo到一个位置,将被遮挡的View展示出来。
这里还有个要注意的地方,就是ScrollTo的参数,先看看函数原型:
两个参数x、y,是要滚动到位置的坐标,注意,它们是绝对坐标。
而我们计算滚动距离的时候,是计算的相对滚动距离。还记得上面的场景2与场景3么,点击输入框,滚动视图,进入场景2,然后点击一个字母,进入场景3,此时,就是一个比较小的相对滚动距离。后面,我们在代码中也有相应注释,要注意理解下哦。
PS:虽然使用上了Android Studio,但是家里电脑确实太慢了,所以demo还是一个Eclipse工程。
下面先给一个图,来讲解下问题所在:
这个图中有四个场景:
第一个场景,是没有弹出软键盘的登录界面,可以看出所有view都正常展示出来了;
第二个场景,弹出了软键盘,此时,下面的密码输入框、登录按钮都被遮挡了;
第三个场景,弹出了软键盘,输入了一个字母,此时,软键盘又增长了一部分,但是用户名输入框也上移了,并没有被遮盖。不同的手机的软键盘不同,我是在华为手机上遇到这种情况,在解决遮挡问题时也要考虑这个场景;
第四个场景,是我们的目标,弹出了软键盘,原来的视图整体上移了,显示出来我们要操作的view。
下面说下解决软键盘遮盖问题的过程:
首先,是希望Android系统有自带的属性,一设置就搞定问题的。
搜索了下,都是说使用WindowSoftInputMode属性,设置为”adjustPan|stateHidden”或者”adjustResize|stateHidden”,经过测试,这种设置对我的布局没有效果,基本与不设置的默认效果相同。软键盘正好在编辑的EditText的下面,会遮挡登录按钮。第二种方法,是使用ScrollView:
在整体布局的外面加一个ScrollView,在文本框的onTouch监听动作中,滚动整个视图。实测问题:
1,监听到onTouch动作后,进行滚动整个视图操作,需要延时才有效。
原因:onTouch时,软键盘还没有弹出,此时滚动到底部与不滚动是一样的效果。需要等软键盘弹出后,界面中的内容超过了一屏幕,此时的滚动才有效。
2,这个延时时间是多少?
不同手机的延时时间不一致,好的手机100ms就可以了,慢的手机延时500ms也不一定每次都有效果。
3,延时带来的问题:
若延时超过300ms,人眼就能感觉出来了:先是软键盘弹出,然后才是视图滚动。用户会感觉有些奇怪:为什么要动作两次呢?
这种方案,可以凑合使用了,可是,我们要做优雅的开发者,继续寻找!
第三种方法:监听布局变化;
既然使用延时不是一个优雅的方案,那么,滚动视图的最好的时间,当然是在布局变化的时刻。这里,可以使用OnGlobalLayoutListener来实现。我们来学习下:
OnGlobalLayoutListener 是ViewTreeObserver的内部类,当一个视图树的布局发生改变时,可以被ViewTreeObserver监听到,这是一个注册监听视图树的观察者(observer),在视图树的全局事件改变时得到通知。
总结为简单一句话:使用OnGlobalLayoutListener可以监听到布局的变化。
监听到布局变化后,我们就可以自由的操作了:
可以外包一个ScrollView来进行滚动,使用一个
scrollView.fullScroll(ScrollView.FOCUS_DOWN)
来滚动到底部。
不过,不使用ScrollView也能进行滚动的,例如LinearLayout也是可以滚动的,你还不知道吧,其实,我也是才知道:最基础的View就有个ScrollTo()函数的。
好了,基础知识准备好了,剩下就是滚动的距离计算了,我们这样来计算:
通过窗体的根View求出总的区域和可视区域,这样就可以计算出被遮挡的区域的高度,如果超过一定的值就判断为软键盘弹出了,然后将根View ScrollTo到一个位置,将被遮挡的View展示出来。
这里还有个要注意的地方,就是ScrollTo的参数,先看看函数原型:
public void scrollTo(int x, int y)
两个参数x、y,是要滚动到位置的坐标,注意,它们是绝对坐标。
而我们计算滚动距离的时候,是计算的相对滚动距离。还记得上面的场景2与场景3么,点击输入框,滚动视图,进入场景2,然后点击一个字母,进入场景3,此时,就是一个比较小的相对滚动距离。后面,我们在代码中也有相应注释,要注意理解下哦。
下面是贴代码的时间了,先展示我的布局xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/ll_loginView" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#FAFAFA" android:orientation="vertical" > <ImageView android:layout_width="fill_parent" android:layout_height="350dp" android:background="#8fE095" android:scaleType="centerInside" android:src="@drawable/logo" /> <View android:layout_width="match_parent" android:layout_height="5dp" android:focusable="true" android:focusableInTouchMode="true" /> <LinearLayout android:layout_width="fill_parent" android:layout_height="300dp" android:orientation="vertical" > <EditText android:id="@+id/userName" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:hint="请输入用户名" android:inputType="text" android:maxLength="18" android:paddingBottom="10dip" android:singleLine="true" android:textColor="#808080" android:text="" android:textSize="18sp" /> <EditText android:id="@+id/userPwd" android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:hint="请输入密码" android:inputType="numberPassword" android:maxLength="20" android:paddingBottom="10dip" android:singleLine="true" android:textColor="#808080" android:text="" android:textSize="18sp" > </EditText> <LinearLayout android:id="@+id/layout03" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:orientation="horizontal" > <CheckBox android:id="@+id/login_check" android:layout_width="wrap_content" android:layout_height="wrap_content" android:checked="true" /> <TextView android:id="@+id/rememberPwd" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="记住用户名" android:textColor="#808080" android:textSize="15sp" /> </LinearLayout> <Button android:id="@+id/btn_login" android:layout_width="300dp" android:layout_height="50dp" android:layout_gravity="center_horizontal" android:layout_marginTop="40dp" android:background="@drawable/login_buton" android:gravity="center" android:text="立 即 登 录" android:textColor="@android:color/background_light" /> </LinearLayout> </LinearLayout>
然后是主Activity:
package com.example.loginTest; import android.app.Activity; import android.graphics.Rect; import android.os.Bundle; import android.view.View; import android.view.ViewTreeObserver; import android.view.Window; import android.widget.Button; import android.widget.LinearLayout; import com.example.loginTest.R; public class MainActivity extends Activity { private Button btn_login; private LinearLayout ll_loginView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); btn_login = (Button) findViewById(R.id.btn_login); ll_loginView = (LinearLayout) findViewById(R.id.ll_loginView ); autoScrollView(ll_loginView, btn_login);//弹出软键盘时滚动视图 } /** * @param root 最外层的View * @param scrollToView 不想被遮挡的View,会移动到这个Veiw的可见位置 */ private int scrollToPosition=0; private void autoScrollView(final View root, final View scrollToView) { root.getViewTreeObserver().addOnGlobalLayoutListener( new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { Rect rect = new Rect(); //获取root在窗体的可视区域 root.getWindowVisibleDisplayFrame(rect); //获取root在窗体的不可视区域高度(被遮挡的高度) int rootInvisibleHeight = root.getRootView().getHeight() - rect.bottom; //若不可视区域高度大于150,则键盘显示 if (rootInvisibleHeight > 150) { //获取scrollToView在窗体的坐标,location[0]为x坐标,location[1]为y坐标 int[] location = new int[2]; scrollToView.getLocationInWindow(location); //计算root滚动高度,使scrollToView在可见区域的底部 int scrollHeight = (location[1] + scrollToView.getHeight()) - rect.bottom; //注意,scrollHeight是一个相对移动距离,而scrollToPosition是一个绝对移动距离 scrollToPosition += scrollHeight; } else { //键盘隐藏 scrollToPosition = 0; } root.scrollTo(0, scrollToPosition); } }); } }
demo代码下载地址:
http://download.csdn.net/detail/lintax/9694929PS:虽然使用上了Android Studio,但是家里电脑确实太慢了,所以demo还是一个Eclipse工程。
参考:
http://blog.csdn.net/yqichang/article/details/11705235相关文章推荐
- Android 输入法键盘和activity页面遮挡问题解决
- Android 输入法键盘和activity页面遮挡问题解决
- Android 输入法键盘和activity页面遮挡问题解决
- Android中如何解决输入法键盘和activity页面遮挡的问题。
- Android 输入法键盘遮挡控件问题的解决办法
- Android 输入法键盘和activity页面遮挡问题解决
- Android 输入法键盘和activity页面遮挡和自动弹出问题解决
- Android 自定义弹出框 EditText获取光标后键盘遮挡,及初始化弹出键盘问题解决
- Android 输入法键盘和activity页面遮挡问题解决
- Android WebView 全屏下 输入框被键盘遮挡 问题解决
- android,键盘遮挡了输入框,完美解决android键盘遮挡问题
- Android 输入法键盘和activity页面遮挡问题解决
- Android 输入法键盘和activity页面遮挡问题解决
- android listview 点击最后两笔item 键盘遮挡问题解决
- Android 输入法键盘和activity页面遮挡问题解决
- Android中如何解决输入法键盘和activity页面遮挡的问题
- Android 输入法键盘和activity页面遮挡问题解决
- Android WebView 软键盘遮挡输入框问题的解决方法
- Android 输入法键盘和activity页面遮挡问题解决
- Android实现登陆页logo随键盘收放动态伸缩(完美解决键盘弹出遮挡控件的问题)