0
votes

i am trying to create animated header where the height, fontSize and position are being changed while scrolling like header of uber

it works but it is not smooth

when i scroll slowly it shakes very fast

constructor:

  constructor(props) {
super(props);
this.state = {
  fontSizeAnimation: new Animated.Value(30),
  positionX: new Animated.Value(0),
  positionY: new Animated.Value(0),
  height: new Animated.Value(0),
  positionAnimation: new Animated.ValueXY(),
  scrollY: 0,
  counter: 0,
}

}

function of animation:

  animateTitle = (e) => {
  const scrollY = e.nativeEvent.contentOffset.y;
  if(scrollY - this.state.scrollY > 5 || scrollY - this.state.scrollY < -5) {
    this.setState({counter: this.state.counter+1})
    this.setState({scrollY});
    Animated.parallel([
      Animated.timing(this.state.height, {
        toValue: this.state.scrollY,
        duration: 0,
        easing: Easing.linear
      }),
      Animated.timing(this.state.fontSizeAnimation, {
        toValue: this.state.scrollY,
        duration: 0,
        easing: Easing.linear
      })
    ]).start(() => {
      this.state.positionAnimation.setValue({
        x: this.state.scrollY > 50? 50 : this.state.scrollY,
        y: this.state.scrollY > 50? -50 : -this.state.scrollY,
      }) 
    })    
  }

}

render function:

  render() {
const interpolatedFontSize = this.state.fontSizeAnimation.interpolate({
  inputRange: [0, 50],
  outputRange: [30, 20],
  extrapolate: "clamp"
});
const interpolatedHeight = this.state.height.interpolate({
  inputRange: [0, 50],
  outputRange: [120, 60],
  extrapolate: "clamp"
});
return (
  <View>
      <Animated.View style={[styles.header, {height: interpolatedHeight}]}>
        <Image source={require("./images/back-button.png")} style={styles.back} />
        <Animated.Text style={[styles.title, { fontSize: interpolatedFontSize, transform: this.state.positionAnimation.getTranslateTransform() }]}>Title</Animated.Text>
      </Animated.View>
      <ScrollView
        onScroll={(e) => this.animateTitle(e)}
        contentContainerStyle={{minHeight: "100%", height: 1000, backgroundColor: "grey"}}
        >
          <View style={{height: 800, backgroundColor: "red", width: "100%", marginBottom: 10}}>
          </View>
      </ScrollView>
  </View>
)

} }

style:

const styles = StyleSheet.create({

back: { position: "absolute", top: 20, left: 10, height: 30, width: 30 }, title: { position: "absolute", paddingTop: 5, top: 60, left: 10 }, header: { position: "relative", backgroundColor:"grey", } });

2
Try to set duration:300 - DevAS

2 Answers

2
votes

Your animations are currently running on JS thread. You can easily move the animations to the native thread by:

Animated.timing(this.state.animatedValue, {
  toValue: 1,
  duration: 500,
  useNativeDriver: true, // <-- Adding this line
}).start();

Using native drivers can give you a performance boost as it clears the JS thread for other tasks. Try it!

0
votes

You should use LayoutAnimation if you want to animate layouts smoothly (height in this case). Here's a link to get you started.