react-native-reanimated icon indicating copy to clipboard operation
react-native-reanimated copied to clipboard

Android: useAnimatedKeyboard listener breaks translucent StatusBar + NavigationBar

Open ChildishForces opened this issue 1 year ago • 2 comments

Description

When using useAnimatedKeyboard applications that take advantage of the full screen by using translucent (absolutely positioned) StatusBar and NavigationBar revert to having solid counterparts. (Full reproduction repo below, no need to follow the steps)

Steps to reproduce

  1. Instantiate a React Native project.
  2. Create the following methods in MainActivity.java:
  private void transparentStatusAndNavigation() {
      //make full transparent statusBar
      if (Build.VERSION.SDK_INT >= 19 && Build.VERSION.SDK_INT < 21) {
          setWindowFlag(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
                  | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, true);
      }
      if (Build.VERSION.SDK_INT >= 19) {
          getWindow().getDecorView().setSystemUiVisibility(
                  View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                          | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                          | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
          );
      }
      if (Build.VERSION.SDK_INT >= 21) {
          setWindowFlag(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
                  | WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, false);
          getWindow().setStatusBarColor(Color.TRANSPARENT);
          getWindow().setNavigationBarColor(Color.TRANSPARENT);
      }
  }

  private void setWindowFlag(final int bits, boolean on) {
      Window win = getWindow();
      WindowManager.LayoutParams winParams = win.getAttributes();
      if (on) {
          winParams.flags |= bits;
      } else {
          winParams.flags &= ~bits;
      }
      win.setAttributes(winParams);
  }
  1. Call from onCreate:
@Override
protected void onCreate(Bundle savedInstanceState) {
  // Rest of logic here
  transparentStatusAndNavigation();
}
  1. Remember to add new imports:
import android.graphics.Color;
import android.view.Window;
import android.view.WindowManager;
import android.view.View;
  1. Use useAnimatedKeyboard and the insets will disappear.

Snack or a link to a repository

https://github.com/ChildishForces/reanimated-bug-repro

Reanimated version

2.10.0

React Native version

0.69.0

Platforms

Android

JavaScript runtime

Hermes

Workflow

Expo bare workflow

Architecture

Paper (Old Architecture)

Build type

Debug mode

Device

Real device

Device model

OnePlus 9 Pro

Acknowledgements

Yes

ChildishForces avatar Sep 30 '22 19:09 ChildishForces

FYI: From my basic investigation I think the following lines may be the culprit

I tried to clone, fix and build, but I think there is something different about the build process of 2.10.0 where remote sources/binaries are included. If someone were to explain how to disable this to me, I'd be happy to implement a check to store the initial value and return it to that, rather than true, and submit a PR.

ChildishForces avatar Oct 03 '22 10:10 ChildishForces

There are many things connected to this.

Are you using expo or expo-dev-client? Are you using react-native-screens and the native stack? If so, make sure you're at minimum version 3.14+. There are still some cases were the old deprecated window flag manipulation is used (even in core react-native). This breaks every usage of the Windows Insets API.

I am using https://github.com/kirillzyusko/react-native-keyboard-controller, which provides basically the same hook. @kirillzyusko and I spent a ton of time to track down this issues and his library also exposes a statusBarTranslucent prop on the provider to fix all of this weird issues. You could give it a try.

hirbod avatar Oct 06 '22 12:10 hirbod

I'll do that and report back, though would love to see this resolved in reanimated, as I like to keep my dependencies as few as possible.

ChildishForces avatar Oct 10 '22 15:10 ChildishForces

@hirbod Sorry, forgot to update! Your provided solution worked perfectly, thanks for your help. Going to leave this issue open, so when the RNR team get round to it they have a summary & repro of the issue for their own hook.

ChildishForces avatar Oct 23 '22 19:10 ChildishForces

I have the same bug. Here is a reproducible code snippet. I'm using the latest RN (0.70.4) and reanimated (2.12.0)

import React from 'react';
import {Button, View, StyleSheet, StatusBar} from 'react-native';
import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';

import {useAnimatedKeyboard} from 'react-native-reanimated';

function HomeScreen({navigation}) {
  return (
    <View
      style={{
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center',
        backgroundColor: 'green',
      }}>
      <Button
        title="Go to Profile"
        onPress={() => navigation.navigate('Notifications')}
      />
    </View>
  );
}

function NotificationsScreen({navigation}) {
  const keyboard = useAnimatedKeyboard(); // <=====
  return (
      <View
        style={{
          flex: 1,
          alignItems: 'center',
          justifyContent: 'center',
          backgroundColor: 'blue',
        }}>
        <Button title="Go back" onPress={() => navigation.goBack()} />
      </View>
  );
}

const Stack = createNativeStackNavigator();

function MyStack() {
  return (
    <Stack.Navigator screenOptions={{headerShown: false}}>
      <Stack.Screen name="Home" component={HomeScreen} />
      <Stack.Screen name="Notifications" component={NotificationsScreen} />
    </Stack.Navigator>
  );
}

export default function App() {
  return (
    <GestureHandlerRootView style={{flex: 1, backgroundColor: 'red'}}>
      <StatusBar
        barStyle="dark-content"
        hidden={false}
        translucent={true}
        backgroundColor="transparent"
      />
      <NavigationContainer>
        <MyStack />
      </NavigationContainer>
    </GestureHandlerRootView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 24,
    backgroundColor: 'blue',
  },
  contentContainer: {
    flex: 1,
    alignItems: 'center',
  },
});

alexco2 avatar Nov 01 '22 22:11 alexco2