Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android: KeyboardAvoidingView white-space on bottom of screen when android:windowTranslucentStatus is set to true #27526

Closed
hrastnik opened this issue Dec 16, 2019 · 23 comments

Comments

@hrastnik
Copy link

KeyboardAvoidingView leaves space on bottom of screen when the keyboard is closed.
This bug manifests when the android:windowTranslucentStatus is set to true. (Note that this is the case for project initialized with Expo)

kav-bug

React Native version:

System:
    OS: macOS 10.15.2
    CPU: (4) x64 Intel(R) Core(TM) i5-4308U CPU @ 2.80GHz
    Memory: 68.76 MB / 8.00 GB
    Shell: 5.7.1 - /bin/zsh
  Binaries:
    Node: 12.4.0 - ~/.nvm/versions/node/v12.4.0/bin/node
    Yarn: 1.19.1 - ~/.nvm/versions/node/v12.4.0/bin/yarn
    npm: 6.13.1 - ~/.nvm/versions/node/v12.4.0/bin/npm
    Watchman: 4.9.0 - /usr/local/bin/watchman
  SDKs:
    iOS SDK:
      Platforms: iOS 13.2, DriverKit 19.0, macOS 10.15, tvOS 13.2, watchOS 6.1
    Android SDK:
      API Levels: 23, 26, 27, 28, 29
      Build Tools: 27.0.3, 28.0.3, 29.0.0
      System Images: android-28 | Intel x86 Atom_64, android-28 | Google APIs Intel x86 Atom, android-29 | Google APIs Intel x86 Atom
  IDEs:
    Android Studio: 3.5 AI-191.8026.42.35.5791312
    Xcode: 11.2.1/11B500 - /usr/bin/xcodebuild
  npmPackages:
    react: 16.9.0 => 16.9.0 
    react-native: 0.61.5 => 0.61.5 
  npmGlobalPackages:
    react-native-cli: 2.0.1

Steps To Reproduce

  1. Initialize a new RN project
  2. Add <item name="android:windowTranslucentStatus">true</item> to android/app/src/main/res/values/styles.xml
  3. Copy/paste the following code to App.js
import React from 'react';
import {TextInput, View, KeyboardAvoidingView} from 'react-native';

export default () => (
  <KeyboardAvoidingView behavior="padding" style={{flex: 1}}>
    <View
      style={{flex: 1, justifyContent: 'center', backgroundColor: 'yellow'}}>
      <TextInput placeholder="Tap here to open keyboard" />
    </View>
  </KeyboardAvoidingView>
);
  1. Run the app using react-native run-android
  2. Open and close the keyboard
  3. Observe the white-space on the bottom of the screen

Describe what you expected to happen:
It's expected for the yellow View to take up the whole space.

Snack, code example, screenshot, or link to a repository:
https://snack.expo.io/@hrastnik/keyboardavoidingview-bug

@patrickreck
Copy link

Have you found a solution to this?

@hrastnik
Copy link
Author

Not really. I set the behaviour to height as it seems to work better sometimes, but it's not a solution.

I'm just waiting if a fix comes soon, otherwise I'll try rolling my own KeyboardAvoidingView.

@MitchellSlavik
Copy link

After some digging, this looks like it was caused by the keyboardDidHide event getting actual values on Android #24947. KeyboardAvoidingView is assuming that event will come back with no value and it will set it's bottom state value to 0. The values in the keyboardDidHide event are those from View.getWindowVisibleDisplayFrame(), which is the visible frame of the device without the statusbar since anything under the status bar would not be visible to the user. This causes the KeyboardAvoidingView to think that there is a keyboard the height of the statusbar still on the screen and causes the white line at the bottom.

@Drzaln
Copy link

Drzaln commented Jan 7, 2020

Have anyone found a solution for this issue?

@dhruv-toptal
Copy link

dhruv-toptal commented Jan 28, 2020

Facing same issue on RN v0.60 and <StatusBar backgroundColor={'transparent'} translucent={true} />

@devstarman
Copy link

Hi, is there any chance that this issue will be addressed soon?
I've switched to EXPO 36.0 recently and started to experience a lot of buggy behavior with KeyboardAvoidingView since :(

@MitchellSlavik
Copy link

@Drzaln @dhruv-toptal @devstarman
Since KeyboardAvoidingView is a purely js implementation, you can work around this issue in the mean time by running your own KeyboardAvoidingView. Here is what I am currently using it is just a slightly modified version of the one in react-native.
https://gist.github.com/MitchellSlavik/0cf342af5711c36d69af5224dba1f7e5

@hrastnik
Copy link
Author

hrastnik commented Feb 9, 2020

I found that behavior="height" works fine and doesn’t leave the white space on the bottom.
However iOS works weird with behavior="height", so the solution is to use:

behavior={Platform.select({ android: "height", ios: "padding" })}

@devstarman
Copy link

@hrastnik you are almost right but unfortunately, I found a bug with behavior="height" on Android and posted it here: #28004

@josmontes
Copy link

Besides the whitespace, does anybody know a workaround on bottom tabs jumping when the keyboard closes?

@devstarman
Copy link

@MitchellSlavik I actually have not noticed your suggestion and I'm pleased to report that it's working fabulously! Thank you very much! The question remains why nobody from react-native team checked this issue reported in multiple posts if the fix is available and only needs to be included into next official release as a fix.

@giregk
Copy link

giregk commented May 20, 2020

@Drzaln @dhruv-toptal @devstarman
Since KeyboardAvoidingView is a purely js implementation, you can work around this issue in the mean time by running your own KeyboardAvoidingView. Here is what I am currently using it is just a slightly modified version of the one in react-native.
https://gist.github.com/MitchellSlavik/0cf342af5711c36d69af5224dba1f7e5

@MitchellSlavik did you or can you create a PR ?

@giregk
Copy link

giregk commented May 20, 2020

Besides the whitespace, does anybody know a workaround on bottom tabs jumping when the keyboard closes?

if you are using @MitchellSlavik 's solution, I found that instead of using his _onKeyboardHide method, if you keep using _onKeyboardChange and replace , at the end of that method, this.setState({bottom: height}) with this.setState({bottom: Platform.OS === "ios" ? height : 0}), there is no jump

@t-fritsch
Copy link

Not sure how this is related, but I noticed the KeyboardAvoidingView also has problems of height/padding restoration when changing orientation on android : rotating the phone from portrait to landscape and then back to portrait results in unwanted spacing at the bottom of the view.

Using @MitchellSlavik hack seems to resolve this issue too ! thanks a lot 🙏

@barnu5
Copy link

barnu5 commented Jun 15, 2020

Also having this issue

@Octaner
Copy link

Octaner commented Jun 22, 2020

Same problem with space on bottom of screen after upgrade RN from 0.60.6 to 0.61.0

@fabOnReact
Copy link
Contributor

fabOnReact commented Jul 7, 2020

While preparing the pull request for this issue I post the following:

#24947 normalized keyboardDidHide return value as following:

image

but the height returned in the below line does not include the StatusBar

image

PixelUtil.toDIPFromPixel(mVisibleViewArea.height()),

I changed the height to 900 in my case and the white bar does not show

I'm confident that I can publish pull request to fix this issue.

@MitchellSlavik is probably right saying that getWindowVisibleDisplayFrame does not include the StatusBar in the computation, this seems to be only applicable when using android:windowTranslucentStatus..

My current understanding is that windowTranslucentStatus makes the window show behind a translucent StatusBar, for this reason the window height is incrased by the StatusBar height.

I'll will find a solution for this issue and publish the pull request within days.

Thanks. Best Regards.

@sanchitos
Copy link

I was working on a pure JS RN app so the approach of @MitchellSlavik was not suitable for me.
If you have the same 'problem' this package saved my life:
https://www.npmjs.com/package/react-native-keyboard-aware-scroll-view

kelset pushed a commit that referenced this issue Sep 29, 2020
…s=true (#29292)

Summary:
This issue fixes #27526, related issue #27089
Avoid returning the wrong screenY coordinates on event keyboardDidHide.
getWindowVisibleDisplayFrame retrieves the overall visible display size in which the window this view is attached to has been positioned in. This takes into account screen decorations above the window, for both cases where the window itself is being position inside of them or the window is being placed under then and covered insets are used for the window to position its content inside. In effect, this tells you the available area where content can be placed and remain visible to users, since anything below the StatusBar is not visible to the user, the method does not work with translucent StatusBar (android:windowTranslucentStatus).

This commit fixes this issues removing the white bar at the bottom of the view when using windowTranslucentStatus.

## Changelog

<!-- Help reviewers and the release process by writing your own changelog entry. For an example, see:
https://github.com/facebook/react-native/wiki/Changelog
-->

[Android] [Fixed] - keyboardDidHide wrong screenY coordinates with windowTranslucentStatus=true

Pull Request resolved: #29292

Test Plan:
Works in all scenarios, but **I did not change RNTester `windowTranslucentStatus`**. I would like to discuss the potential breaking changes connected to not using [getWindowVisibleDisplayFrame](https://developer.android.com/reference/android/view/View#getWindowVisibleDisplayFrame(android.graphics.Rect)) with `keyboardDidHide`.

I would be happy to build an alternative functionality to calculate the WindowVisibleDisplayFrameHeight under request from the Facebook Team.

**WITHOUT** `android:windowTranslucentStatus`

| **BEFORE** |
|:-------------------------:|
|  <img src="https://user-images.githubusercontent.com/24992535/86804255-0eca4680-c077-11ea-8c79-95ba297d05ba.gif"  />|

| **AFTER** |
|:-------------------------:|
| <img src="https://user-images.githubusercontent.com/24992535/86804265-10940a00-c077-11ea-8cb8-a304cc5de363.gif"  /> |

**WITH** `android:windowTranslucentStatus`

| **BEFORE** |
|:-------------------------:|
|  <img src="https://user-images.githubusercontent.com/24992535/86804458-3a4d3100-c077-11ea-8f3e-7c43eaa08d70.gif"  height="" />|

| **BEFORE (log)** |
|:-------------------------:|
|  <img src="https://user-images.githubusercontent.com/24992535/86806330-0d018280-c079-11ea-9266-c3bcf23a35da.png"  height="" />|

| **AFTER** |
|:-------------------------:|
| <img src="https://user-images.githubusercontent.com/24992535/86804464-3b7e5e00-c077-11ea-8487-34c87f076e5f.gif" height="" /> |

| **AFTER (log)** |
|:-------------------------:|
| <img src="https://user-images.githubusercontent.com/24992535/86806042-c4e26000-c078-11ea-9c3c-cac5319bef65.png" height="" /> |

RNTester **WITHOUT** `android:windowTranslucentStatus`

| **BEFORE** | **AFTER** |
|:-------------------------:|:-------------------------:|
|  <img src="https://user-images.githubusercontent.com/24992535/86805348-176f4c80-c078-11ea-8e2a-e2d84af5c278.gif"  width="300" height="" />| <img src="https://user-images.githubusercontent.com/24992535/86805324-13432f00-c078-11ea-9e70-fa2606eee86b.gif" width="300" height="" /> |

I remain available to do improvements. Thanks a lot. Fabrizio.

Reviewed By: JoshuaGross

Differential Revision: D22521125

Pulled By: mdvacca

fbshipit-source-id: e2cb90163abb1baa00b1916e431971b011522565
@wmonecke
Copy link

@MitchellSlavik Your implementation is not consistent in Android. Works on API 28 but not 29.

@fabOnReact
Copy link
Contributor

This issue was fixed with release 0.63.3 with my pr #29292

I quote the message from @andres-torres-marroquin in #30770 (comment)

I wonder about the behavior parity between iOS and Android, since on Android you could get multiple calls from keyboard events, if happens that you have more than one ReactRootView, I wonder if there is a way to do it as it is done on iOS, where you get the event triggered just once. (therefore depending of the app, might be a performance hit on Android)

I'm proposing to write a pr to react-native-navigation as explained in my post #30770 (comment)

I would be happy to receive your feedback as I'm evaluating several potential solutions, including writing a pr to reverse this change or find an alternative solution. I will update #30770 with any new idea, please join the conversation. Thanks a lot ☮️ 🙏

I'll send pr to react-native-navigation to override checkForKeyboardEvents in ReactView, if those are the views used for this scenario.

public class ReactView extends ReactRootView implements IReactView, Renderable {
    @Override
    protected void checkForKeyboardEvents() {
        super.checkForKeyboardEvents();
        // copy below logic
    }
 }

https://github.com/wix/react-native-navigation/blob/15c7a7e799f3cff9ad83b782dccc92aa1fe8a523/lib/android/app/src/main/java/com/reactnativenavigation/react/ReactView.java#L23-L43

checkForKeyboardEvents should look like this

private void checkForKeyboardEvents() {
getRootView().getWindowVisibleDisplayFrame(mVisibleViewArea);
final int heightDiff =
DisplayMetricsHolder.getWindowDisplayMetrics().heightPixels - mVisibleViewArea.bottom;
boolean isKeyboardShowingOrKeyboardHeightChanged =
mKeyboardHeight != heightDiff && heightDiff > mMinKeyboardHeightDetected;
if (isKeyboardShowingOrKeyboardHeightChanged) {
mKeyboardHeight = heightDiff;
sendEvent(
"keyboardDidShow",
createKeyboardEventPayload(
PixelUtil.toDIPFromPixel(mVisibleViewArea.bottom),
PixelUtil.toDIPFromPixel(mVisibleViewArea.left),
PixelUtil.toDIPFromPixel(mVisibleViewArea.width()),
PixelUtil.toDIPFromPixel(mKeyboardHeight)));
return;
}
boolean isKeyboardHidden = mKeyboardHeight != 0 && heightDiff <= mMinKeyboardHeightDetected;
if (isKeyboardHidden) {
mKeyboardHeight = 0;
sendEvent(
"keyboardDidHide",
createKeyboardEventPayload(
PixelUtil.toDIPFromPixel(mVisibleViewArea.height()),
0,
PixelUtil.toDIPFromPixel(mVisibleViewArea.width()),
0));
}
}

@MayoudP
Copy link

MayoudP commented Feb 9, 2021

This issue was fixed with release 0.63.3 with my pr #29292

Does this version ( 0.63.3) and fixe suggestion fixed the issues in Android 11 where Keyboard doesn't show up in KeyboardAvoidingView ? Or does it seems to you a completely different bug ? thx

@fabOnReact
Copy link
Contributor

@MayoudP open and issue with a Minimum Reproducible Example and I'll have a look into it. Thanks a lot 👍

@Sargnec
Copy link

Sargnec commented May 11, 2021

#29292

I'm using router flux with react native version 0.63.3 but still having this issue

@facebook facebook locked as resolved and limited conversation to collaborators Oct 2, 2021
@react-native-bot react-native-bot added the Resolution: Locked This issue was locked by the bot. label Oct 2, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet