1.使用范围

2.遇到的坑

3.解决方法


废话不多说,近期项目中坑爹需求,要求,键盘弹出后,页面内容,滚动到固定的位置,接下来就说下思路

1.在清单文件中设置inputsoft 的 几种组合。发现的不符合,而且还有一个的问题,使用adjustpan 模式,会造成,键盘弹出,和隐藏时,屏幕有黑色背影。
2.监听键盘的显隐,通过显隐来操作view 的滚动。当然的,要配合系统提供的组件scrollView 来。
3.使用系统提供的工具进行页面模块高度计算,然后算出,键盘弹出后,scrollView 滚动的距离。 方式三只是在方式二的基础上进行扩展。
4. Android 5.0 meterial design 的 toolbar中自带的效果(由于项目最低版本支持到4.1 ,所有暂时没有引入 5.0的效果,这里不进行讨论)

Inputsoft 的几种组合参数:

5.”stateUnspecified”
6.软键盘的状态(是否它是隐藏或可见)没有被指定。系统将选择一个合适的状态或依赖于主题的设置。
7.这个是为了软件盘行为默认的设置。
8.”stateUnchanged”
9.软键盘被保持无论它上次是什么状态,是否可见或隐藏,当主窗口出现在前面时。
10.”stateHidden”
11.当用户选择该Activity时,软键盘被隐藏——也就是,当用户确定导航到该Activity时,而不是返回到它由于离开另一个Activity。
12.”stateAlwaysHidden”
13.软键盘总是被隐藏的,当该Activity主窗口获取焦点时。
14.”stateVisible”
15.软键盘是可见的,当那个是正常合适的时(当用户导航到Activity主窗口时)。
16.”stateAlwaysVisible”
17.当用户选择这个Activity时,软键盘是可见的——也就是,也就是,当用户确定导航到该Activity时,而不是返回到它由于离开另一个Activity。
18.”adjustUnspecified”
19.它不被指定是否该Activity主窗口调整大小以便留出软键盘的空间,或是否窗口上的内容得到屏幕上当前的焦点是可见的。系统将自动选择这些模式中一种主要依赖于是否窗口的内容有任何布局视图能够滚动他们的内容。如果有这样的一个视图,这个窗口将调整大小,这样的假设可以使滚动窗口的内容在一个较小的区域中可见的。这个是主窗口默认的行为设置。
20.”adjustResize”
21.该Activity主窗口总是被调整屏幕的大小以便留出软键盘的空间
22.”adjustPan”
23.该Activity主窗口并不调整屏幕的大小以便留出软键盘的空间。相反,当前窗口的内容将自动移动以便当前焦点从不被键盘覆盖和用户能总是看到输入内容的部分。这个通常是不期望比调整大小,因为用户可能关闭软键盘以便获得与被覆盖内容的交互操作。

当然还是建议去官网查看的。更详细。经常用的也就 adjustResize 模式和 adjustPan。区别就是一个是压缩view中内容。一个是调整屏幕大小。(产生黑色背景 bug)

解决产生黑色背景的方法。就是获得 activity.getrRootView( ) .setBackgroundColor( )就可以,不要问我,为什么我知道。别人都这么干的,简单粗暴

方式二:

监听EditerText TOUCH 事件。进行scrollView 的滚动。具体滚动的位置。就要你自己定义了,对于标注要求不太严格的可以使用这种方式。当监听到touch 事件,就用hander 发送消息,让最外层包裹的scrollView 进行滚动。缺点:有时候scrollView 不听使唤,不滚动。


进行屏幕高度动态计算,计算滚动距离,通过监听ViewTree的变化。屏幕变化来达到监听键盘事件,从而达到本文交互效果。

代码:

package com.example.pullkeytotop;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.ScrollView;

public class KeyWordUtils {
/**
* 弹出键盘时滚动到界面指定位置
* @param activity
* 当前Activity
* @param lyRootID
* 所在根布局ID
* @param vID
* 要滚动到的控件ID
* @param svID
* 控件所在ScrollView ID
* @author gpy
*/
@SuppressLint("NewApi")
public static void pullKeywordTop(final Activity activity,final int lyRootID,final int vID,final int svID){
ViewGroup ly = (ViewGroup) activity.findViewById(lyRootID);
//获取屏幕高度,根据经验,输入法弹出高度一般在屏幕1/3到1/2之间
final int defaultHeight = ((WindowManager)activity.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getHeight();
final int mKeyHeight = defaultHeight/4;
ly.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) {
//获取根布局前后高度差
int height = oldBottom-bottom;
ScrollView sv = (ScrollView)activity.findViewById(svID);
if(height>mKeyHeight) {//当高度差大于屏幕1/4,认为是输入法弹出变动,可能会有特殊机型会失败
final int lybottom = bottom;
sv.post(new Runnable() {//用post防止有时输入法会自动滚动覆盖我们手动滚动
@Override
public void run() {
ScrollView runSv = (ScrollView)activity.findViewById(svID);
//获取要滚动至的控件到屏幕顶部高度
View v = (View)activity.findViewById(vID);
int[] loca = new int[2];
v.getLocationOnScreen(loca);
//这种通知栏高度获取方法必须在布局构建完毕后才能生效,否则获取为0
Rect frame = new Rect();
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
int statusBarHeight = frame.top;
// 要滚动的距离=控件距屏幕顶部距离+控件高度-输入法弹出后的activity高度-通知栏高度
int scrollHeight = loca[1] + v.getHeight() - lybottom - statusBarHeight;
if(scrollHeight>0){
runSv.scrollBy(0, scrollHeight);
}

}
});
}else if(-height>mKeyHeight){//当输入法收起,回滚回顶部
sv.scrollTo(0,0);
}
}
});



}
}

不要说scrollView 这么滚动。ScrollTo ( ) ,scrollby() ,smoothScrollTo( ),但是如果需要自定义滚动时间,就需要自己开动脑筋想方法了,本文基于系统默认动画时间。250 ms。具体为什么是250 毫秒。可以自行度scrollView 中代码。

上文blog中方法,有些许欠缺,获取状态栏的高度方法。

感谢以上blog作者贡献