windowSoftInputMode not resizing properly
swolford opened this issue ยท 27 comments
First and foremost, I absolutely love your drawer library. It is the easiest drawer I've had the pleasure of using! However... I've discovered a bug when interacting with EditText and opening the soft keyboard.
I've uploaded a sample project here:
https://github.com/swolford/MaterialDrawerDemo
I've wrapped the section named "Keyboard Demo" in a ScrollView because my fragments will have many items so the user will need to scroll. The keyboard overlays the layout. The expected behaviour is the ScrollViewer scrolls to the current EditText.
"Keyboard Demo #2" is the same layout as Keyboard Demo without the ScrollView. Users won't be able to scroll and the keyboard pushes the entire activity up.
I have included in styles.xml two themes. DemoTheme01 inherits your theme and DemoTheme02 is a direct copy of yours (from your library source) with windowSoftInputMode set.
DemoTheme02 works and has the scrolling functionality I expect, but the drawer header image does not extend behind the status bar... I'm not sure why directly copying your theme works, but inheriting it and setting a property doesn't.
I'd like to have both scrolling to the correct EditText and the drawer header image extending behind the status bar.
Any ideas?
@swolford thank you so much for the detailed report.
I checked the source and debugged it on my phone.
I found out that the adjustResize
function is not working as soon as
<item name="android:windowTranslucentStatus">true</item>
I had to try some combinations of the theme and your app until i found this.
So i did some detailed research and found out that this only works if you set android:fitsSystemWindows="true"
within your layout. We can't use this with the current MaterialDrawer implementation because if you use this the layout won't show behind the statusbar, because it ads the margin to it. So it will show the background color behind the statusbar.
So the next thing was to try fixing this by layout or code. But no luck.
So with some further digging i found out that this seems to be a bug with Android (not sure about this but read more about it here: http://stackoverflow.com/questions/21092888/windowsoftinputmode-adjustresize-not-working-with-translucent-action-navbar/22266717#22266717)
and that the only solution to get the whole combination working for all phones is to use a custom Layout called ScrimsInsetLayout used in the Google IO app. https://github.com/google/iosched/blob/master/android/src/main/java/com/google/samples/apps/iosched/ui/widget/ScrimInsetsFrameLayout.java
I'll start reworking everything tomorrow. So hopefully the first release which contains this layout and the fix for your issue is out tomorrow.
Sorry for your troubles.
@mikepenz thank you for looking into this! I have been banging my head for a while trying to figure out what was going on. Apart from this one issue, your library is the easiest and cleanest library to use for a Materal Drawer implementation. Font-Awesome being included is a very nice touch.
Thank you again. :)
@swolford i'll give you feedback as soon as i get it working ;)
Thank you so much. It also includes the GoogleMaterial design icons ;).
-- https://github.com/mikepenz/Android-Iconics
Sorry for the troubles
@swolford i made a lot of changes. now it would work with adjustPan
but still not with adjustResize
i do some additional things. i hope i can find a solution
@swolford some hours later i have still no real answer to fix your issue.
As far as i've found this is a real issue but it is working as intended: https://code.google.com/p/android/issues/detail?id=5497
So either you use no translucent statusbar. or you try to get the functionality working with adjustPan or with an alternative layout or something like this.
Here's a description how you can test the latest v2.5.0 with the ScrimInsetsLayout. Perhaps you are able to find a configuration which will work. :/
@mikepenz, sorry for the headache I have caused you! I have been looking at some of Google's own apps and trying to figure out what their behaviour is.
- Google Inbox: Full height, translucent statusbar. When keyboard is open, drawer is inaccessible. I assume they switched off adjustResize (as per one of the suggestions in the Google Code page you linked) and disabled the drawer.
- GMail: Same as Google Inbox.
- Google Hangouts - Same as Inbox and GMail.
- Google Keep: Full height, translucent statusbar. When keyboard is open, drawer is accessible (but closes keyboard when opened), and statusbar is still translucent with the drawer image behind it! Whatever Google did with Google Keep is the solution. Too bad it is not open-source!
I will try some other things and get back to you. Thanks for your time!
@swolford no problem. it's a problem and somehow we should be able to solve it :D.
Probably let the drawer manage the keyboard behavior too, and disabling enabling fullscreen would work. hmmmm. it is at least an idea.
Google Keep. Hmmm i think decompiling won't help with googles apps :D
thanks you so much
@swolford within google keep (notes) i found out an interesting behavior. If you have a long input and open the keyboard the view will add the space at the bottom to the view. so this area stays scrollable after the keyboard was closed. (if you scroll up it won't be scrollable anymore)
so it seems they react on the keyboard open and add a spacing at the bottom of the list.
@swolford you won't believe it but i found a hack which fixes this issue. I'll update the sample from the MaterialDrawer later ;)
@swolford source is up and you can check it here: https://github.com/mikepenz/MaterialDrawer/blob/master/app/src/main/java/com/mikepenz/materialdrawer/app/SimpleFragmentDrawerActivity.java
So as a detailed description what it does, or how i came to this solution. I tried a lot of different things, disabling the fullscreen or changing ui flags if the drawer is not shown or many additional things, but nothing changed. just a few things made the ui look ugly. so i checked some google apps as you did, and as i wrote above i checked the google keep app.
Everytime the keyboard showed up it changed the height of the containing view (adding enough padding/margin at the bottom) so i checked how i can do the same for our app.
I wrote a listener which reacts on the layout height change and calculates if it could be a keyboard. at the moment it reacts starting with 100dp (SwiftKey with the smallest setting takes 240dp) i then use the difference to the main height change and add the padding to the containing view. not to the root of the application but to the container for the fragments. So here's the code which does the magic:
Whole source can be found here: https://github.com/mikepenz/MaterialDrawer/blob/aa9136fb4f5b3a80460fe5f47213985026d20c88/library/src/main/java/com/mikepenz/materialdrawer/util/KeyboardUtil.java
private View decorView;
private View contentView;
public KeyboardUtil(Activity act, View contentView) {
this.decorView = act.getWindow().getDecorView();
this.contentView = contentView;
//only required on newer android versions. it was working on API level 19
if (Build.VERSION.SDK_INT >= 19) {
decorView.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener);
}
}
public void enable() {
if (Build.VERSION.SDK_INT >= 19) {
decorView.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayoutListener);
}
}
public void disable() {
if (Build.VERSION.SDK_INT >= 19) {
decorView.getViewTreeObserver().removeOnGlobalLayoutListener(onGlobalLayoutListener);
}
}
//a small helper to allow showing the editText focus
ViewTreeObserver.OnGlobalLayoutListener onGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
Rect r = new Rect();
//r will be populated with the coordinates of your view that area still visible.
decorView.getWindowVisibleDisplayFrame(r);
//get screen height and calculate the difference with the useable area from the r
int height = decorView.getContext().getResources().getDisplayMetrics().heightPixels;
int diff = height - r.bottom;
//if it could be a keyboard add the padding to the view
if (diff != 0) {
// if the use-able screen height differs from the total screen height we assume that it shows a keyboard now
//check if the padding is 0 (if yes set the padding for the keyboard)
if (contentView.getPaddingBottom() != diff) {
//set the padding of the contentView for the keyboard
contentView.setPadding(0, 0, 0, diff);
}
} else {
//check if the padding is != 0 (if yes reset the padding)
if (contentView.getPaddingBottom() != 0) {
//reset the padding of the contentView
contentView.setPadding(0, 0, 0, 0);
}
}
}
};
It took a lot of time to hint everything down and get something working. but yeah i like it ;)
Holy mackerel, you're good! Thanks! I'm going to try it now and report back. :D
@swolford sounds good :) let me know. For api level 10 i've disabled this within the util because there the adjustResize is still working normal :D
@swolford Oh you have used the SNAPSHOT for 2.5.0 already so it's in your cache sorry. I'll just push a new snapshot with v2.5.0-1-SNAPSHOT to the repo.
I will release this version tomorrow. first i want to make sure the thing i've changed work the way everyone expects them.
@swolford the new SNAPSHOT is up.
compile('com.mikepenz.materialdrawer:library:2.5.0-1-SNAPSHOT@aar') {
transitive = true
}
@mikepenz - This works fantastically on my HTC One M7 running Lollipop 5.0.2 (API 21). On my HTC Optimus Showtime running Jellybean 4.0.4 (API 15) there was too much of a gap.
The layout resizes beautifully and scrolling is enabled on the One as you can see below:
And the focused EditText goes way too high up on the Optimus Showtime. Scrolling is also inside that teeny tiny area.
Here is how the layout is supposed to look normally:
I changed
new KeyboardUtil(this, findViewById(R.id.fragment_container));
to
//react on the keyboard for lollipop or above
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
new KeyboardUtil(this, findViewById(R.id.fragment_container));
since we really only need the translucent statusbar and such for Lollipop and above and it worked beautifully. :)
Thank you again!
So i will need to change this in the util :D
Which api version is your "Optimus Showtime"?
EDIT: ah sorry just saw you wrote it on the top :D API 15
It is API 15. I would suggest testing on other physical devices with varying screen sizes if you have them (or access to them). This one has a very small (4.3" / 10,6cm) screen so that might be why the display metrics were off. Maybe there is a middle ground somewhere. As for right now, setting the resize to only L seems to work. :D
No no no. It has probably nothing to do with the resolution.
If you check the source. i already disable it vor API 10 because i found that adjustResize is still working at this api level. perhaps it's the same for API 15. The emulator of API16 does not show a keyboard ^^
Aha, gotcha! I thought about resolution because many apps do not look right on that particular phone. Most layouts look stretched, scrunched or too big.
I cannot thank you enough for this. I'm looking forward to all future updates to this library. ๐
@swolford ok so i found out how to get the keyboard to show in the emulator. The KeyboardUtil will now only do a difference on API Level >= 19. so you should be able to remove your check
Changes are in the new snapshot
compile('com.mikepenz.materialdrawer:library:2.5.0-2-SNAPSHOT@aar') {
transitive = true
}
Thank you so much :)
This is absolutely beautiful. I had the same exact issue, except in my case I was writing a custom Activity that implemented onApplyWindowInsets, but the child fragment's container view wouldn't consume the insets in dispatchApplyWindowInsets. Will be trying this out.
Thanks again.
KeyboardUtil works like a charm.
Thanks.
@mikepenz Thank you so much for your great job, I'm really appreciate. Until now everything is fine, but Galaxy M20. The contentview gets higher and causing it to remain partially behind navigation bar.
The fact that it's 2020 and I'm here to look for workaround for this issue (with API 29 out) is rather concerning.