前一段时间,项目中有一个页面,如图所示
图片中的最下方的按钮,取消预约,这两个按钮,在正常的页面中是正常显示的,但是会出现头部的ToolBar会被顶出页面,也就是在弹出输入框的时候,然后测试小伙伴就给我提了bug,没有办法,只好去寻找解决办法;
1.最开始寻找的解决办法,就是在androidMnifest,清淡文件中加入
"android:windowSoftInputMode="adjustPan|stateHidden"
,但是没啥用啊,后来又详细的查看了相对应的其他几个参数,也都挨个试验了,最后失败;只好再次去另寻他法
2.第二个方法就是进行让整个页面进行滑动,NestedScrollView使用相关的,将整个页面除了toolbar,都包裹进去,然后在弹出输入框的时候进行页面的整体调整,最后勉强通过测试,但是展示效果不理想,而且按钮也跟着滑动,明显的不符合自己的需求;
3.实在没有办法了,继续百度,找方法吧;然后就找到了本片文章的主题ViewTreeObserver,
ViewTreeObserver 注册一个观察者来监听视图树,当视图树的布局、视图树的焦点、视图树将要绘制、视图树滚动等发生改变时,ViewTreeObserver都会收到通知,ViewTreeObserver不能被实例化,可以调用View.getViewTreeObserver()来获得。
官方文档的描述ViewTreeObserver是用来监听一些全局变化的。
在 ViewTreeObserver 中,包含了以下几个接口:
interface ViewTreeObserver.OnGlobalFocusChangeListener
interface ViewTreeObserver.OnGlobalLayoutListener
interface ViewTreeObserver.OnPreDrawListener
interface ViewTreeObserver.OnScrollChangedListener
interface ViewTreeObserver.OnTouchModeChangeListener
具体的使用方法
View decorView = getWindow().getDecorView();
View contentView = findViewById(Window.ID_ANDROID_CONTENT);
decorView.getViewTreeObserver().addOnGlobalLayoutListener(getGlobalLayoutListener(decorView, contentView));
在这里开始进行监听的编写,然后实现对应的监听方法,对其中的对应的数据contentView.setPadding,设置好他的偏移量,这样就可以在弹出输入框的时候,不会让我们的toolbar被顶上去,也不会遮挡住我们的EditText,而且按钮也不会被遮盖
private ViewTreeObserver.OnGlobalLayoutListener getGlobalLayoutListener(final View decorView, final View contentView) {
return () -> {
Rect r = new Rect();
decorView.getWindowVisibleDisplayFrame(r);
int height = decorView.getContext().getResources().getDisplayMetrics().heightPixels;
int diff = height - r.bottom;
if (diff != 0) {
if (contentView.getPaddingBottom() != diff) {
contentView.setPadding(0, 0, 0, diff);
} else {
contentView.setPadding(0, 0, 0, 0);
}
};
}
然后在我以为大功告成的时候,我们的测试小伙伴又提bug了,在小米的刘海屏手机上
这两个按钮,只展示了头部的一丢丢,取消 和预约按钮的字基本都看出出来;这就很烦人,但是没有办法之后继续加判断
这里获取是不是小米的机型判断
public static boolean isMiui() {
String manufacturer = Build.MANUFACTURER;
//这个字符串可以自己定义,例如判断华为就填写huawei,魅族就填写meizu
return !"xiaomi".equalsIgnoreCase(manufacturer);
}
然后在ViewTreeObserver之中加上相关的判断,然后大功告成
private ViewTreeObserver.OnGlobalLayoutListener getGlobalLayoutListener(final View decorView, final View contentView) {
return () -> {
Rect r = new Rect();
decorView.getWindowVisibleDisplayFrame(r);
int height = decorView.getContext().getResources().getDisplayMetrics().heightPixels;
int diff = height - r.bottom;
if (diff != 0) {
if (contentView.getPaddingBottom() != diff) {
if (isMiui()) {
contentView.setPadding(0, 0, 0, diff);
}else{
contentView.setPadding(0, 0, 0, 0);
}
}
} else {
if (contentView.getPaddingBottom() != 0) {
contentView.setPadding(0, 0, 0, 0);
}
}
};
}
开始以为ViewTreeObserver,这个看起来肯定很难,毕竟看起来好像很难的样子,但是实际使用时,沉下心,一切问题就有不太大了.