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

Children position does not animate when animating view's width using Layout Animations #6280

Open
itsramiel opened this issue Jul 16, 2024 · 2 comments
Labels
Area: Layout Animations Platform: iOS This issue is specific to iOS Repro provided A reproduction with a snippet of code, snack or repo is provided

Comments

@itsramiel
Copy link

Description

When a view's width is animated using Layout Animations(entry, exit, layout transitions), children views position do not update for the intermediate states but instead jump to the final state.

example code(available in branch main of linked repo):

function ExitAnimation(values: ExitAnimationsValues): LayoutAnimation {
  "worklet";
  return {
    initialValues: {
      width: values.currentWidth,
    },
    animations: {
      width: withTiming(0, { duration: 1000 }),
    },
  };
}

function EnterAnimation(values: EntryAnimationsValues): LayoutAnimation {
  "worklet";
  return {
    initialValues: {
      width: 0,
    },
    animations: {
      width: withTiming(values.targetWidth, { duration: 1000 }),
    },
  };
}

export default function App() {
  const [isOnlyRight, setIsOnlyRight] = useState(true);

  return (
    <View style={styles.screen}>
      <View style={styles.container}>
        {isOnlyRight ? null : (
          <Animated.View
            exiting={ExitAnimation}
            entering={EnterAnimation}
            style={styles.button}
          >
            <Text style={styles.text}>Left</Text>
          </Animated.View>
        )}
        <Animated.View
          style={styles.button}
          layout={LinearTransition.duration(1000)}
        >
          <Text style={styles.text}>Right</Text>
        </Animated.View>
      </View>
      <Button title="Toggle" onPress={() => setIsOnlyRight(!isOnlyRight)} />
      <StatusBar style="auto" />
    </View>
  );
}

Check the video here. I have a button that toggles between rendering 1 view and 2 views. Both views have their widths animated using Entry/Exit or Layout Transition, but the problem is that the position of the text inside them does not animate with the view.

The resetted border radius seems to be another bug

Simulator.Screen.Recording.-.iPhone.15.-.2024-07-16.at.20.23.44.mp4

However if the view's width was animated from within useAnimatedStyle, it works(available in branch feat/works):

const availableWidth = Dimensions.get("window").width - 32 - 10;
export default function App() {
  const [isOnlyRight, setIsOnlyRight] = useState(true);

  const leftStyle = useAnimatedStyle(() => {
    return {
      width: withTiming(isOnlyRight ? 0 : availableWidth / 2),
    };
  }, [isOnlyRight]);

  const rightStyle = useAnimatedStyle(() => {
    return {
      width: withTiming(isOnlyRight ? availableWidth : availableWidth / 2),
    };
  }, [isOnlyRight]);

  return (
    <View style={styles.screen}>
      <View style={styles.container}>
        <Animated.View style={[styles.button, leftStyle]}>
          <Text style={styles.text} numberOfLines={1}>
            Left
          </Text>
        </Animated.View>
        <Animated.View style={[styles.button, rightStyle]}>
          <Text style={styles.text}>Right</Text>
        </Animated.View>
      </View>
      <Button title="Toggle" onPress={() => setIsOnlyRight(!isOnlyRight)} />
      <StatusBar style="auto" />
    </View>
  );
}
Simulator.Screen.Recording.-.iPhone.15.-.2024-07-16.at.20.31.35.mp4

I expect the first code to behave like the second one but it doesnt. I prefer to write code as in the first example as it is more declarative and I dont need to set a specific width to the view and instead just have it adapt

Steps to reproduce

  1. clone the repo
  2. run the app
  3. inspect the behavior shown in video

Snack or a link to a repository

https://github.com/itsramiel/Animating-Views/tree/main

Reanimated version

3.10.1

React Native version

0.74.3

Platforms

iOS

JavaScript runtime

Hermes

Workflow

Expo Go

Architecture

Paper (Old Architecture)

Build type

Debug app & dev bundle

Device

iOS simulator

Device model

No response

Acknowledgements

Yes

@github-actions github-actions bot added Repro provided A reproduction with a snippet of code, snack or repo is provided Platform: iOS This issue is specific to iOS labels Jul 16, 2024
@itsramiel itsramiel changed the title Children position does not animate when animating view's width Children position does not animate when animating view's width using Layout Animations Jul 16, 2024
@MatiPl01
Copy link
Member

Hey!

Currently, you have to specify the layout property of all components that will be affected during the layout animation. In order to properly animate the text inside the Animated.View on the right, you will have to add the same layout prop to the Animated.Text component nested inside.

See this example:

export default function App() {
  const [isOnlyRight, setIsOnlyRight] = useState(true);

  const transition = LinearTransition.duration(1000);

  return (
    <View style={styles.screen}>
      <View style={styles.container}>
        {isOnlyRight ? null : (
          <Animated.View
            exiting={ExitAnimation}
            entering={EnterAnimation}
            style={styles.button}>
            <Text style={styles.text}>Left</Text>
          </Animated.View>
        )}
        <Animated.View style={styles.button} layout={transition}>
          <Animated.Text layout={transition} style={styles.text}>
            Right
          </Animated.Text>
        </Animated.View>
      </View>
      <Button title="Toggle" onPress={() => setIsOnlyRight(!isOnlyRight)} />
    </View>
  );
}

Example recording after change

Simulator.Screen.Recording.-.iPhone.15.Pro.-.2024-07-17.at.10.06.10.mp4

Remarks

Layout animations are a bit buggy. You can see that it works only for the button on the right side. Changing the Text component to Animated.Text with the layout property inside the button on the left side has no effect.

I can also see that the border radius of the button on the left side is not applied. I tested on the new architecture (fabric) as well and the border radius works properly in there.

cc @piaskowyk

@itsramiel
Copy link
Author

In order to properly animate the text inside the Animated.View on the right, you will have to add the same layout prop to the Animated.Text component nested inside.

Thanks for letting me know but that is really cumbersome and if as you mentioned

You can see that it works only for the button on the right side. Changing the Text component to Animated.Text with the layout property inside the button on the left side has no effect.

then yeah that is unfortunate.


I can also see that the border radius of the button on the left side is not applied. I tested on the new architecture (fabric) as well and the border radius works properly in there.

Yeah exactly I noted this too above the first video

image

I really hope that declarative just work and I can use Layout Animations with ease knowing that it behavior is the same when I change the width no matter if I animate using Entry/Exit, Layout Transitions, or 'useAnimatedStyle

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

No branches or pull requests

2 participants