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

[WIP] Handle status bar without is status bar translucent android option

Open maciekstosio opened this issue 1 year ago • 1 comments

Summary

During the discussion #5851 it was suggested that we could handle status bar without passing special flag. I attached observer that listens to StatusBar changes and keep track if the color is translucent and what is its height. Thanks to that I can change top insets automatically. The PR is WIP - if we decide to go with it I need to remove unused flag or deprecate it

Before without useAnimatedKeyboard Before with useAnimatedKeyboard After

Test plan

Turn of navigation headers if visible, and then you use this Example:

Example
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 [statusBarTranslucent, setStatusBarTranslucent] = useState(false);
  const keyboard = useAnimatedKeyboard();

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

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

  return (
    <Animated.View
      style={[
        styles.container,
        animatedStyles,
        { justifyContent: 'flex-end', borderWidth: 5, borderColor: '#ff0', backgroundColor: "#222" },
      ]}>
      <StatusBar
        barStyle="default"
        hidden={statusBarHidden}
        backgroundColor={statusBarTranslucent ? 'transparent' : undefined}
        translucent={statusBarTranslucent}
      />
      <Button
        title="Toggle statusBackgroundColor"
        onPress={() => setStatusBarTranslucent((hidden) => !hidden)}
      />
      <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' },
});

maciekstosio avatar Apr 11 '24 09:04 maciekstosio

This solution works, but we're investigating this in terms of performance, as in current state it may cause problems.

maciekstosio avatar Jul 03 '24 09:07 maciekstosio

@maciekstosio recently I had to use react-native-keyboard-controller and react-native-avoid-softinput and they both had issues with useAnimatedKeyboard and edge to edge setup with react-native-unistyles. The status bar is flickering when useAnimatedKeyboard does it's magic causing weird layout effects.

Both input handlers set decorFitsSystemWindow dynamically but on react-native-unistyles @2.8.1 it's static -> false.

some more info on rn-avoid-softinput:

  • https://github.com/mateusz1913/react-native-avoid-softinput/issues/200#issuecomment-2007527099

Just wanted to bring this to your attention.

cc: @jpudysz

efstathiosntonas avatar Jul 03 '24 12:07 efstathiosntonas

Using ViewTreeObserver.OnDrawListener is not performant. It triggers the callback multiple times. After months of debugging insets IMO there are two reliable ways to measure it:

  • WindowInsetsCompat - but requires decorFitsSystemWindow set to false
  • measuring root view and decor view and compare them - but we need to handle multiple edge cases

@maciekstosio if you want I can share some knowledge here

jpudysz avatar Jul 03 '24 12:07 jpudysz

Using ViewTreeObserver.OnDrawListener is not performant. It triggers the callback multiple times. After months of debugging insets IMO there are two reliable ways to measure it:

  • WindowInsetsCompat - but requires decorFitsSystemWindow set to false
  • measuring root view and decor view and compare them - but we need to handle multiple edge cases

@maciekstosio if you want I can share some knowledge here

Yeah, that's why it's on hold for so long :D Although I'm not sure if those two solution are feasible - we have decorFitsSystemWindow(false) to observe keyboard height, but as far as I remember the problem with transparent status bar is that insets do not change, just the background and I couldn't find a way to observe that (other then on every draw). Anyway, I'm more than happy to discuss it with you, I'll write you.

maciekstosio avatar Jul 22 '24 11:07 maciekstosio