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

Call useAnimatedKeyboard hook breaks screen area #5811

Closed
TomCorvus opened this issue Mar 19, 2024 · 8 comments · Fixed by #5851
Closed

Call useAnimatedKeyboard hook breaks screen area #5811

TomCorvus opened this issue Mar 19, 2024 · 8 comments · Fixed by #5851
Assignees
Labels
Platform: Android This issue is specific to Android Repro provided A reproduction with a snippet of code, snack or repo is provided

Comments

@TomCorvus
Copy link

Description

Hello,

On my project, I call useAnimatedKeyboard hook to get keyboard height and push my content accordingly with an animated component, but I notice that calling this hook breaks app display area. In the repo, I hide status bar to make the problem more visible. Comment the hook call, and the problem is fixed.

share_1657837725477601185

On the repo, I installed [react-native-avoid-softinput](https://github.com/mateusz1913/react-native-avoid-softinput) because I have the same problem with the setShouldMimicIOSBehaviorhook. Only on Android too.

Steps to reproduce

  1. Init a fresh project
  2. Install REA
  3. call useAnimatedKeyboard hook

Snack or a link to a repository

https://github.com/TomCorvus/RNSAV

Reanimated version

3.8.1

React Native version

0.73.6

Platforms

Android

JavaScript runtime

V8

Workflow

React Native

Architecture

None

Build type

Release app & dev bundle

Device

Real device

Device model

Google Pixel 7

Acknowledgements

Yes

@github-actions github-actions bot added Platform: Android This issue is specific to Android Repro provided A reproduction with a snippet of code, snack or repo is provided labels Mar 19, 2024
@tomekzaw
Copy link
Member

Hey @TomCorvus, thanks for reporting this issue. It might be a regression caused by recent changes in the implementation of useAnimatedKeyboard hook. @piaskowyk promised to take a look at it soon.

@kesha-antonov
Copy link

Same here 🙏

@tomekzaw
Copy link
Member

tomekzaw commented Apr 5, 2024

@TomCorvus @kesha-antonov can you please check if #5851 resolves the problem?

@TomCorvus
Copy link
Author

@tomekzaw No, not for me. I updated the repro repo and apply patch.
https://github.com/TomCorvus/RNSAV
It seems that it fix one of the problems. The warning appears now in the safe area view, but the status bar is not includes in it.
If I comment useAnimatedKeyboard hook, the problem disappears.

Uncommented Commented
share_5824319798550667949 share_1107710790529520659

@TomCorvus
Copy link
Author

useAnimatedKeyboard({ isStatusBarTranslucentAndroid: true }); fix the problem.

github-merge-queue bot pushed a commit that referenced this issue May 1, 2024
## Summary

Should fix: #5811

Keyboard height seems to be improperly calculated. Based on my
investigation it seems that ` WindowInsetsCompat.Type.ime()` includes
height of the keyboard + bottom navigation. What Reanimated does
currently is checking if navigation bar is visible
(`KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_HOME);`) and then
subtracts the bottom inset `int keyboardHeight = DiphasNavigationBar ?
contentBottomInset - systemBarBottomInset : contentBottomInset;`. But to
my understanding `hasNavigationBar` is always true, thus when keyboard
is hidden keyboard height becomes `-contentBottomInset`. So I changed
the navigation height to be `Math.max(0, keyboardHeightDip)`

Additionally in WindowInsetsManager.java I applied default paddings and
added padding bottom which should help correctly position element from
the bottom.

### Remarks
- on older androids < 11, hidden status bar rolls back to adjustPan
keyboard behavior
- flag `isStatusBarTranslucentAndroid` doesn't seems to do anything when
screen has native header (`headerShown: true`)

### Examples before vs after 

*Adding useAnimatedKeyboard breaks the layout*
|Before|After|
|-|-|
|<video
src="https://github.com/software-mansion/react-native-reanimated/assets/11800297/bb3bec01-7e57-451f-8d43-2271739402eb"
/>|<video
src="https://github.com/software-mansion/react-native-reanimated/assets/11800297/46eff754-5eea-41d0-9ffe-20657cdc4e0c"
/>|

*After closing the keyboard there is unexpected gap (negative height)*
|Before|After|
|-|-|
|<video
src="https://github.com/software-mansion/react-native-reanimated/assets/11800297/284d0be5-5cb2-439a-b0f3-5881525f0ec6"
/>|<video
src="https://github.com/software-mansion/react-native-reanimated/assets/11800297/5e6ebf04-6d53-4284-8ad0-d079fbe242bd"
/>|

*When StatusBar is hidden keyboard nor working properly on Android 10 -
not fixed but not a regression*
|Before|After|
|-|-|
|<video
src="https://github.com/software-mansion/react-native-reanimated/assets/11800297/75041b95-7db9-4a12-89f5-a68ab5006ea9"
/>|<video
src="https://github.com/software-mansion/react-native-reanimated/assets/11800297/608ac6e6-9dcc-40bc-8f41-d6132e21b006"
/>|

## Test plan

<details>
<summary>Example showing the problem</summary>

```jsx
import React, { useEffect, useState } from 'react';
import Animated, {
  useAnimatedKeyboard,
  useAnimatedReaction,
  useAnimatedStyle,
} from 'react-native-reanimated';
import {
  Platform,
  StatusBar,
  StyleSheet,
  TextInput,
  View,
  Text,
  Button,
} from 'react-native';

export default function EmptyExample() {
  const [statusBarHidden, setStatusBarHidden] = useState(false);
  const keyboard = useAnimatedKeyboard();

  const animatedStyles = useAnimatedStyle(() => ({
    transform: [{ translateY: -keyboard.height.value }],
  }));

  useAnimatedReaction(
    () => {
      return keyboard.height.value;
    },
    (currentValue) => console.log(currentValue)
  );

  useEffect(() => {
    StatusBar.setHidden(statusBarHidden);
  }, [statusBarHidden]);

  return (
    <Animated.View
      style={[
        styles.container,
        animatedStyles,
        { justifyContent: 'flex-end', borderWidth: 5, borderColor: '#ff0' },
      ]}>
      <Button
        title="Toggle StatusBar"
        onPress={() => setStatusBarHidden((hidden) => !hidden)}
      />
      <Button
        title="Show Warning"
        onPress={() => console.warn('WARNING!!!!')}
      />
      <View
        style={[
          styles.center,
          {
            height: 200,
            backgroundColor: '#f0f',
            borderWidth: 5,
            borderColor: '#0ff',
          },
        ]}>
        <Text>{`Android ${Platform.constants['Release']}`}</Text>
        <TextInput placeholder="Test" />
      </View>
    </Animated.View>
  );
}

const styles = StyleSheet.create({
  container: { flex: 1 },
  center: { justifyContent: 'center', alignItems: 'center' },
});

```

</details>
@fax1ty
Copy link

fax1ty commented Aug 1, 2024

How about navigation bar? @TomCorvus

When isStatusBarTranslucentAndroid is true it applies bottom padding according to the navigation inset and sets top margin to 0.

What if I want to fill up the whole screen?

@TomCorvus
Copy link
Author

Not sure about that but if you configure your manifest and set full screen mode, there is no bottom padding because your navigation inset doesn't exist.

@fax1ty
Copy link

fax1ty commented Aug 6, 2024

But what if I want to have a bottom navigation, but have the content underneath it
@piaskowyk Is it possible to make isNavigationBarTranslucentAndroid?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Platform: Android This issue is specific to Android Repro provided A reproduction with a snippet of code, snack or repo is provided
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants