Objective
Development has been done for a long time, always inevitably encounter various pits.
On the way to Android development, the "soft keyboard blocks the input box" is a long-drawn pit-come on, we look slowly.
Introductory article
Base
The basic situation: at the bottom of the page there is a edittext, if do not do any processing, then the soft keyboard pops up, it is possible to block the edittext.
The handling of this situation is very simple, just set the activity in the Androidmanifest file: android:windowSoftInputMode
The value adjustPan
or adjustResize
you can, like this:
<activity android:name=".MainActivity" android:windowSoftInputMode="adjustPan" > ...</activity>
Generally speaking, they can solve the problem, of course, adjustPan
with adjustResize
a slightly different effect.
adjustPan
is to translate the entire interface upward, so that the input box is exposed, does not change the layout of the interface;
adjustResize
is to recalculate the interface size after the popup soft keyboard, the equivalent is to use less interface area to display content, the input box is generally natural inside.
↑↑↑ok, this is just getting started, basically all Android engineers on the planet can handle it.
Don't worry, look down there ~
Plus WebView try? The Pit is coming ...
In the introductory article above, the soft keyboard is triggered by the native edittext. And in H5, hybrid almost has become the app standard, we often encounter the situation is: Soft keyboard is triggered by the page elements in the WebView pop-up .
Situation description
That's when things get complicated:
- First,
非全屏模式
when the page is in the case, the activity settings are adjustPan
invalidated.
- Second, the page is
全屏模式
the case, the adjustPan
following adjustResize
will fail.
--Explain that the 全屏模式
page is full screen, including application or activity using the fullscreen theme, using "state color coloring", "immersive status bar", "Immersive Mode" and so on – in short, Basically, this problem arises when the app itself takes over the control of the status bar.
The following table provides a brief list of specific situations.
Why does the form say it's a pit? "Issue 5497"
This is not what Google expects in the table above, and the ideal scenario is that they all work correctly-so this is actually a bug in the Android system itself.
Why does the article say it's a hole at the beginning?
-because this bug was reported from the android1.x era (2009), it has not been repaired until today's Android7.0 (2016) .../(ㄒoㄒ)/
It can be said that this is not only a pit, but also an official digging hole ~
"Issue 5497", details Portal? Issue 5497-android-webview adjustresize Windowsoftinputmode breaks when activity is fullscreen-android Open Source Pr Oject-issue Tracker-google Project Hosting
Of course, no matter who dug the pit, eventually the developers to solve.
After encountering a pit, there are two ways to go: hide, or fill.
Hiding in a pit posture
As shown earlier, the condition of the pit is: activity with WebView 全屏模式
or adjustPan
mode.
Then the position of the pit is very simple--
If there is webview in the activity, do not use 全屏模式
it, and set its Windowsoftinputmode value as adjustResize
well.
How, isn't it very simple???
20130927092846557 Pits Posture
But there are always times when it is necessary to be with WebView, and at this time 全屏模式
, to avoid the pit, we need a new pits posture. Fortunately, the developer's wisdom is endless, the pit has been around for so many years, or someone has found some solutions.
Androidbug5497workaround
I personally think that the best solution is this: Androidbug5497workaround, only need a magical AndroidBug5497Workaround
class.
Look at the name to know, it is specifically used to deal with the "5497" problem, the use of steps is super simple:
AndroidBug5497Workaround
to copy a class to a project
- Add a sentence to the OnCreate method of activity that requires pits
AndroidBug5497Workaround.assistActivity(this)
.
After testing, basically on each Android version is available, the effect is basically the same as set adjustResize
.
Look at a comparison chart:
Effect Comparison Chart
An activity page from our app that uses WebView 全屏模式
, from left to right: no soft keyboard style, soft keyboard blocking the input box effect, and the final effect after using Androidbug5497workaround.
What is the principle of it?
This cool Androidbug5497workaround class, in fact, is not very complex, only dozens of lines of code, first posted here:
PublicClassAndroidbug5497workaround {For more information, see https://code.google.com/p/android/issues/detail?id=5497To use the This class, the simply Invoke Assistactivity () on the Activity that already have its content view set.PublicStaticvoidAssistactivity(Activity activity) {New Androidbug5497workaround (activity); }Private View mchildofcontent;Privateint usableheightprevious;Private Framelayout.layoutparams Framelayoutparams;PrivateAndroidbug5497workaround(Activity activity) {Framelayout content = (framelayout) Activity.findviewbyid (Android. R.id.content); Mchildofcontent = Content.getchildat (0); Mchildofcontent.getviewtreeobserver (). Addongloballayoutlistener (New Viewtreeobserver.ongloballayoutlistener () {PublicvoidOngloballayout() {possiblyresizechildofcontent ();}}); Framelayoutparams = (framelayout.layoutparams) mchildofcontent.getlayoutparams (); }PrivatevoidPossiblyresizechildofcontent() {int usableheightnow = Computeusableheight ();if (usableheightnow! = usableheightprevious) {int usableheightsanskeyboard = Mchildofcontent.getrootview (). GetHeight ();int heightdifference = Usableheightsanskeyboard-usableheightnow;if (Heightdifference > (usableheightsanskeyboard/4)) { //keyboard probably just became visible framelayou Tparams.height = usableheightsanskeyboard-heightdifference; } else { //keyboard probably just became hidden framelayoutparams.height = Usableheightsanskeyboard;} Mchildofco Ntent.requestlayout (); usableheightprevious = Usableheightnow; }} private int computeusableheight() {rect r = new Rect (); mchildofcontent.getwindowvisibledisplay Frame (R); return (r.bottom-r.top); //Full-screen mode: Return R.bottom}}
The code is basically doing a few things:
1. Find the Activity root view
Check the Entry code:
FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);mChildOfContent = content.getChildAt(0);
The view in the first line android.R.id.content
is the root view of the area that the developer can control on all Android activity interfaces.
- If activity is
全屏模式
, then Android. R.id.content is the full screen area.
- If the activity is normal
非全屏模式
, then Android. R.id.content are all areas that are full except for the status bar.
- In other cases, such as activity is the pop-up window, or 7.0 after the split screen style, etc., Android.r.id.content is also the scope of the pop-up window or half of the screen--these cases are less, for the time being not considered.
We often use the Setcontentview (view view)/setcontent (int layres) is actually to put our designated view or layres into the android.r.id.content inside, become its sub-View.
So, then, the second line content.getchildat (0) gets, in fact, to mChildOfContent
get the view that we put in the Setcontentview.
2. Set a listener monitor view tree change
//简化了写法 possiblyResizeChildOfContent();});
View.getviewtreeobserver () can get an ViewTreeObserver
object-this object is an observer, specifically to listen to some of the changes that have taken place in the current view tree. What is registered here addOnGlobalLayoutListener
is a notification callback when the current view tree's global layout (globallayout) changes, or when the view visibility state changes.
--"soft keyboard Popup" is a source that will trigger this event. (soft keyboard Popup will change the Globallayout)
In other words, you can now hear the "soft keyboard pop-up" event.
3. After the interface changes, get the "available height"
When the soft keyboard pops up, the next thing is to get the changed interface 可用高度
(the height that can be used by the developer to display the content).
Look directly at the code:
private int computeUsableHeight() { Rect rect = new Rect(); mChildOfContent.getWindowVisibleDisplayFrame(rect); // rect.top其实是状态栏的高度,如果是全屏主题,直接 return rect.bottom就可以了 return (rect.bottom - rect.top); }
View.getwindowvisibledisplayframe (rect rect), this line of code can get to the rect--is the interface to remove the title bar, remove the soft keyboard block, the rest of the rectangular area-the red box area.
Rect area
↑ can also be seen:
- The Rect.top value is actually the height of the title bar. (In fact, this is often used as a way to get the height of the title bar)
- Screen height-rect.bottom, is the height of the soft keyboard. (The method for getting the soft keyboard height also appears)
At this point, there are:
全屏模式
Under, 可用高度
= Rect.bottom
- Non
全屏模式
, 可用高度
= Rect.bottom-rect.top
4. Last step, reset height
What we have calculated 可用高度
is the height of the interface that is currently visible in visual effects. But the actual height of the current interface is more than the 可用高度
distance to a soft keyboard.
So, the final step is to set the interface height to--it's done 可用高度
.
Privatevoidpossiblyresizechildofcontent () { int usableheightnow = Computeusableheight (); if (usableheightnow! = usableheightprevious) {int Usableheightsanskeyboard = Mchildofcontent.getrootview (). GetHeight (); int heightdifference = Usableheightsanskeyboard-usableheightnow; if (Heightdifference > (usableheightsanskeyboard/4)) { Span class= "hljs-comment" >//keyboard probably just became visible framelayoutparams.height = Usableheightsanskeyboard- Heightdifference; } else {//keyboard probably just became hidden Framelayoutparams.height = Usableheightsanskeyboard; } mchildofcontent.requestlayout (); usableheightprevious = Usableheightnow; } }
The above code adds a "Heightdifference > (USABLEHEIGHTSANSKEYBOARD/4)" judgment, this is to remove unnecessary interference. Because there are many reasons to trigger the Ongloballayout event, it is not only the pop-up change of the soft keyboard, but also the hidden display changes of various sub-view, which have limited influence on the height of the interface. With this judgment, only the height of the interface changes more than 1/4 of the screen height, it will be reset height, basic can ensure that the code only responds to the soft keyboard pop-up.
Summarize
To sum up, that's it:
- Normal activity (without webview), direct use
adjustpan
oradjustResize
- If with WebView:
- A) if not
全屏模式
, you can useadjustResize
- b) If it is, it is
全屏模式
used AndroidBug5497Workaround
for processing.
OK, the above is a "soft keyboard block input box" of the crawl of the pit trip.
Useful Links:
https://code.google.com/p/android/issues/detail?id=5497
http://stackoverflow.com/a/19494006
Https://developer.android.com/reference/android/view/ViewTreeObserver.html
About the Author:
Http://www.barryzhang.com
Https://barryhappy.github.io
Android Crawl Pit Tour: The ultimate solution for soft keyboard blocking input box problems