Android Crawl Pit Tour: The ultimate solution for soft keyboard blocking input box problems

Source: Internet
Author: User

This article by Barryzhang original, at the same time starting in diycode.cc, barryzhang.com, Github.com/barryhappy, non-commercial reprint please indicate the author and the original link.

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

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.

    • adjustPanis to translate the entire interface upward, so that the input box is exposed, does not change the layout of the interface;
    • adjustResizeis 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:

    1. First, 非全屏模式 when the page is in the case, the activity settings are adjustPan invalidated.
    2. 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 do you think 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???

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:

    1. AndroidBug5497Workaroundto copy a class to a project
    2. 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:

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:

 Public  class androidbug5497workaround {    //For more information, see https://code.google.com/p/android/issues/detail?id=5497    simply invoke Assistactivity () on a Activity that already have its content view set.     Public Static void assistactivity(Activity activity) {NewAndroidbug5497workaround (activity); }PrivateView mchildofcontent;Private intusableheightprevious;PrivateFramelayout.layoutparams Framelayoutparams;Private Androidbug5497workaround(Activity activity) {Framelayout content = (framelayout) Activity.findviewbyid (Android.        R.id.content); Mchildofcontent = Content.getchildat (0); Mchildofcontent.getviewtreeobserver (). Addongloballayoutlistener (NewViewtreeobserver.ongloballayoutlistener () { Public void Ongloballayout() {possiblyresizechildofcontent ();        }        });    Framelayoutparams = (framelayout.layoutparams) mchildofcontent.getlayoutparams (); }Private void possiblyresizechildofcontent() {intUsableheightnow = Computeusableheight ();if(Usableheightnow! = usableheightprevious) {intUsableheightsanskeyboard = Mchildofcontent.getrootview (). GetHeight ();intHeightdifference = Usableheightsanskeyboard-usableheightnow;if(Heightdifference > (usableheightsanskeyboard/4)) {//keyboard probably just became visibleFramelayoutparams.height = usableheightsanskeyboard-heightdifference; }Else{//keyboard probably just became hiddenFramelayoutparams.height = Usableheightsanskeyboard;            } mchildofcontent.requestlayout ();        usableheightprevious = Usableheightnow; }    }Private int Computeusableheight() {Rect r =NewRect (); Mchildofcontent.getwindowvisibledisplayframe (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:

    privateintcomputeUsableHeight() {        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.

↑ 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 可用高度 .

    Private void possiblyresizechildofcontent() {intUsableheightnow = Computeusableheight ();if(Usableheightnow! = usableheightprevious) {intUsableheightsanskeyboard = Mchildofcontent.getrootview (). GetHeight ();intHeightdifference = Usableheightsanskeyboard-usableheightnow;if(Heightdifference > (usableheightsanskeyboard/4)) {//keyboard probably just became visibleFramelayoutparams.height = usableheightsanskeyboard-heightdifference; }Else{//keyboard probably just became hiddenFramelayoutparams.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:

    1. Normal activity (without webview), direct use adjustpan oradjustResize
    2. 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

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.