您的当前位置:首页正文

android 软键盘显示和隐藏造成页面跳闪问题的解决方案

2024-11-07 来源:个人技术集锦

一、分析问题

1.为什么会闪?

首先图像切换主要用的无非就是ViewA.setVisibility(GONE) 和 ViewB.setVisbility(VISIBLE),如果不涉及到软键盘,正常状况下本就应该会闪,也就是说,只要有图像切换,必会闪,这是正常的。

2.为什么会跳?

安卓的软键盘SoftInput其实是一个dalog,它的弹出和缩回这两个动画是有持续时间的。当你切换界面的指令与显隐键盘的指令操作过于接近时(也就是调了切换界面的方法后紧接着调了隐藏键盘的方法),会导致键盘还没完成显隐的操作时,切换页面的操作缺已经执行完了。所以不管你先切换页面还是先显隐键盘,切换页面的操作总是要比显隐键盘先完成!

那么就造成了键盘还没缩回,但页面上会突然乱入一个View(View:你想切换到的页面,或者你setVisibity(VISIBLE)的那个view),然后键盘才慢慢缩回,这样从视觉效果上,就会错觉View向上方闪一下,然后才出现在它该出现的位置。

二、解决方案:

1.非主流但很有意义的方案:

一开始我也在想,为啥手Q、微信、钉订这些玩意的聊天切面就没这个问题?在网上找方案,都是抄袭和转载,还有很多所谓“高仿微信聊天键盘”等等的东西,都围绕着ViewTreeObserver和GlobalLayoutListener,然后通过页面板块高度的减差计算得出键盘的高度,最后动态地设置显示的页面高度等于键盘高度,还要定死输入框的高度。这种方案一看就是大牛写出来,然后被各种转载和抄袭的。此方案的好处很多,可以让像我这样的菜鸟深入到安卓底层,学到很多东西,而且符合观察者模式。但是缺点也很明显,就是逻辑复杂,代码量大,效率低。

该方案教程:

2.微信、手Q这些玩意的主流解决方案:

有没有更简洁的方法呢?想到这,学院派应该会去找第三方包了吧。。但是作为一个野路子(苦逼完全自学派),为了理解里面的逻辑,为了减少包体积,为了提高效率增强动效,想到了去看环信的EaseUI源码?

先看代码,发现代码写的很有美感,很整齐清晰,逻辑也非常的清晰,这里给环信赞一个,但为啥文档写的那么屎? 

对于键盘的处理,环信并没有用ViewTreeObserver!

再看布局:

 

同样只是用了android:layout_alignParentBottom="true"这个属性而已,跟我没有一点不同。

最后,顺着event去找,终于发现了小秘密:

/**
 * show or hide emojicon
 */
protected void toggleEmojicon() {
    if (chatExtendMenuContainer.getVisibility() == View.GONE) {
        hideKeyboard();
        handler.postDelayed(new Runnable() {
            public void run() {
                chatExtendMenuContainer.setVisibility(View.VISIBLE);
                chatExtendMenu.setVisibility(View.GONE);
                emojiconMenu.setVisibility(View.VISIBLE);
            }
        }, 50);
    } else {
        if (emojiconMenu.getVisibility() == View.VISIBLE) {
            chatExtendMenuContainer.setVisibility(View.GONE);
            emojiconMenu.setVisibility(View.GONE);
        } else {
            chatExtendMenu.setVisibility(View.GONE);
            emojiconMenu.setVisibility(View.VISIBLE);
        }

    }
}

可以看到,环信只是简单的先隐藏了键盘,然后在50毫秒后才执行了切换页面的操作,就是如此简单!此时你再去看看我们前面分析的问题,会惊讶的发现这延后的50毫秒完美的解决了问题2!

拿起手机,观察环信、微信、手Q,你还会发现另外一个共同的现象,就是它们的emoj区域和获取媒体区域的高度都比系统软键盘的高度要低!

那么最后总结一下就是:1.先隐藏软键盘;2.隔上个几十毫秒再切换页面;3.页面不要高于软件盘的高度(一般在600以下)完活!

野路子精神万岁!

3.最理想化的解决方案(未尝试):

此方案应该是效率最高,页面效果最为顺滑的。不过我虽然想通了,但是最近项目时限紧,没有时间去实现了,备注一下,以后试试!

经过观察和调适,我发现,显隐软键盘会造成整个页面重绘,并且切换布局会造成页面重绘两次(隐藏ViewA重绘一次,显示ViewB再重绘一次),那么跳闪就可以理解为:在Activity前两次重绘时,只是完成了view的切换,而第三次重绘才是改变键盘(第三次重绘时,给键盘施加了动画)。

那么我们很容易就可以想到,如果把切换页面和隐藏键盘放在同一个Acitity重绘中,不就看不到闪烁了嘛!!

顺着这个思路想,我先想到了Activity,但是明显dalog应该与activity同级,而键盘就是个dalog,那么目标就应该是activity的父级window对象了!

如果能找到键盘缩回的动画,是不是就可以借用给界面?是不是就能时时监听键盘高度变化?最后让输入框做个跟随就行了!

想法很好,可惜没空实现,先mark一下吧。

转载于:https://my.oschina.net/JiangTun/blog/916955

显示全文