Collapse header with section list in react native

Viewed 19

I want to achieve this animation using section list on scroll in react native.

Here is an example of food panda. This is their initial screen: Initial Position

On scrolling the section list their header collapse and it becomes like this: On Scrolling

Here is the code of my RestaurantDetail screen:

export default function RestaurantDetail({navigation, route}) {

  const headerHeight = 400;
  const headerFinalHeight = 100;

  const scrollY = useRef(new Animated.Value(0)).current;

  const offset = headerHeight - headerFinalHeight;

  const translateHeader = scrollY.interpolate({
    inputRange: [0, offset],
    outputRange: [0, -offset],
    extrapolate: 'clamp',
  });
  
  useEffect(() => {
    return navigation.addListener('focus', () => {
      getRestaurantDetail();
      if (user) {
        getCart();
      }
    });
  }, []);

  const onScrollY = e => {
    scrollY.setValue(e.nativeEvent.contentOffset.y);
    headerHeight - e.nativeEvent.contentOffset.y;
    console.log('Height', scrollY);
  };

  const onScroll = ({viewableItems}) => {
    setActiveTab(viewableItems[0].section.title);
    console.log('viewableItems', viewableItems[0].section.title);
  };
return (
    <View style={{backgroundColor: 'white', flex: 1}}>
      <Animated.View
        style={{
          backgroundColor: 'white',
          height: headerHeight,
          position: 'absolute',
          transform: [{translateY: translateHeader}],
        }}>
        <Header restaurantDetail={detail} />
        <View style={{flexDirection: 'row', justifyContent: 'space-between'}}>
          <MainImage restaurantDetail={detail} />
          <TouchableOpacity
            onPress={() => navigation.navigate('RestaurantInfo', detail)}>
            <Rating />
          </TouchableOpacity>
        </View>
        <TouchableOpacity
          onPress={() => navigation.navigate('RestaurantInfo', detail)}>
          <Title restaurantDetail={detail} />
        </TouchableOpacity>
        <HeaderTabs
          activeTab={activeTab}
          setActiveTab={setActiveTab}
          data={itemList}
          ref={ref}
        />
      </Animated.View>
      <View style={{paddingTop: headerHeight}}>
        <SectionListeg
          restaurantDetail={detail}
          activeTab={activeTab}
          setActiveTab={setActiveTab}
          navigation={navigation}
          onScroll={onScroll}
          onScrollY={onScrollY}
          data={itemList}
          scrollEventThrottle={16}
        />
      </View>
      {showView && (
        <View style={styles.box}>
          <View style={styles.viewCartView}>
            <TouchableOpacity
              activeOpacity={0.7}
              onPress={() => navigation.navigate('Cart', true)}>
              <View style={styles.viewCartBtn}>
                <View style={styles.counterView}>
                  <Text style={styles.text}>
                    {cart.cart ? cart.cart.length : cart.length}
                  </Text>
                </View>
                <Text style={styles.text}>View your cart</Text>
                <Text style={styles.text}>{'Rs. ' + cart.sub_total}</Text>
              </View>
            </TouchableOpacity>
          </View>
        </View>
      )}
      <SafeAreaView
        style={{
          position: 'absolute',
          top: 0,
          left: 0,
          right: 0,
          backgroundColor: transparent ? 'transparent' : 'white',
        }}>
        <TopBar navigation={navigation} shouldShow={shouldShow} name={name} />
      </SafeAreaView>
    </View>
  );
}

const styles = StyleSheet.create({
  viewCartView: {
    width: '100%',
    height: 100,
    backgroundColor: 'white',
    position: 'absolute',
    bottom: 0,
    borderTopRightRadius: 10,
    borderTopLeftRadius: 10,
    alignItems: 'center',
    justifyContent: 'center',
    elevation: 5,
  },
  headerContainer: {
    // position: 'absolute',
  },
  box: {
    // ...
    shadowColor: '#000',
    shadowOffset: {width: 0, height: 2},
    shadowOpacity: 1.0,
    shadowRadius: 3,
    elevation: 5,
  },
  viewCartBtn: {
    width: '90%',
    height: 50,
    backgroundColor: Colors.secondary,
    alignSelf: 'center',
    borderRadius: 10,
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-evenly',
  },
  counterView: {
    width: 30,
    height: 30,
    borderRadius: 50,
    borderWidth: 1.5,
    borderColor: 'white',
    justifyContent: 'center',
    alignItems: 'center',
  },
  text: {color: 'white', fontSize: 16, fontWeight: '700'},
});

Here is the code of my Section List:

const SectionListeg = ({
  navigation,
  onScroll,
  data,
  scrollEventThrottle,
  activeTab,
  onScrollY,
  setIndex,
  setActiveTab,
  restaurantDetail,
  shouldShow,
  branchId,
}) => {
  const headerHeight = 400;
  const headerFinalHeight = 100;
  const offset = headerHeight - headerFinalHeight;
  const scrollY = useRef(new Animated.Value(0)).current;
  const translateHeader = scrollY.interpolate({
    inputRange: [0, offset],
    outputRange: [0, -offset],
    extrapolate: 'clamp',
  });

  const renderItem = ({item, index}) => {
    return (
      <Item
        item={item}
        navigation={navigation}
        restaurantDetail={restaurantDetail}
      />
    );
  };
  return (
    <SectionList
      sections={data}
      showsVerticalScrollIndicator={false}
      scrollEnabled={true}
      keyExtractor={(item, index) => {
        // console.log('Key Index', item.title);
        if (item.id) {
          return item.id;
        }
      }}
      renderItem={renderItem}
      onViewableItemsChanged={onScroll}
      onScroll={onScrollY}
      stickySectionHeadersEnabled={false}
      renderSectionHeader={({section: {title}}) => (
        <Text style={styles.header}>{title}</Text>
      )}
    />
  );
};

const Item = ({item, navigation, restaurantDetail}) => (
  <View style={styles.item}>
    <TouchableOpacity
      activeOpacity={0.7}
      style={{flexDirection: 'row', width: '100%'}}
      onPress={() => onItemPress(item, navigation, restaurantDetail)}>
      <View style={{flexDirection: 'row'}}>
        <View style={{width: '70%'}}>
          <Text style={styles.title}>{item.title}</Text>
          <Text numberOfLines={2} style={styles.description}>
            {item.description}
          </Text>
          <Text style={{marginTop: 5, color: Colors.black}}>
            PKR {item.price}
          </Text>
        </View>
        <View style={{width: '30%'}}>
          <Image
            style={styles.image}
            source={{uri: 'https://uat.yallafood.pk/' + item.imageUrl}}
          />
        </View>
      </View>
      <View
        style={{
          width: '100%',
          height: 1,
          position: 'absolute',
          bottom: 0,
          left: 0,
          backgroundColor: Colors.grey,
        }}
      />
    </TouchableOpacity>
  </View>
);

const styles = StyleSheet.create({
  container: {
    flex: 1,
    marginHorizontal: 16,
  },
  item: {
    backgroundColor: '#fff',
    marginVertical: 5,
    paddingStart: 20,
    paddingEnd: 20,
    flexDirection: 'row',
    justifyContent: 'space-between',
  },
  header: {
    fontSize: 26,
    backgroundColor: '#fff',
    marginLeft: 20,
    fontWeight: 'bold',
    color: 'black',
  },
  title: {
    fontSize: 20,
    color: 'black',
  },
  description: {
    fontSize: 14,
    color: Colors.grey,
    marginTop: 5,
    // width: '50%',
  },
  image: {
    width: 80,
    height: 80,
    borderRadius: 10,
    marginBottom: 10,
    alignSelf: 'flex-end',
  },
});

This is my initial Screen: My initial screen

This is my screen on Scroll: On scroll

Any help will be appreciated.

0 Answers
Related