Vinit Rana
Vinit Rana

Reputation: 1

Nested Scorll Problem in React native using nested FlatList

`The problem here is the nested scroll View. In the UI there is a parent Flat list as a vertical, inside it child flat list with a Horizontal and then there is one scrollView with a Horizontal

what we are expecting, we are unable to Scroll the inner Scroll View, every time the Flatlist with the Horizontal will scroll.

I have tried to implement the Flatist instead of the inner Scroll View! still, it didn't work! also used react-native-gesture-handler but the issue persisted.

Following is the code for FlatList :`

  <FlatList data={Object.entries(ExpData)}
                showsVerticalScrollIndicator={false}
                showsHorizontalScrollIndicator={false}
                nestedScrollEnabled
                renderItem={({ item }: any) => {
                    let key = item[0];
                    let val = item[1];
                    let mealId = item[1][0].meal_category_id;
                    return <View>
                        <View style={styles.expContainerHeader}>
                            <Text style={styles.nearByHeaderText}> {key} </Text>
                            <TouchableOpacity style={{ flexDirection: "row" }} 
           onPress={() => handleSeeAll(mealId, key)}>
                                <Text style={styles.seeAllText}>See All</Text>
                                <Image
                                    source={IMG_CONST.seeAll}
                                    style={styles.seeAll}
                                    testID="seeAllIconId"
                                />
                            </TouchableOpacity>
                        </View>
                        <FlatList data={val}
                            horizontal
                            showsVerticalScrollIndicator={false}
                            showsHorizontalScrollIndicator={false}
                            nestedScrollEnabled
                            renderItem={({ item }: any) => {
                                let id = item.id;
                                const CurrencyPriceIndicator =
                      (priceindicator: any, currency: any) => {
                                    let currencysymbol = '';

                                    if (priceindicator == 1) {
                                        currencysymbol = `${currency}`;
                                    } else if (priceindicator == 2) {
                                        currencysymbol = `${currency}${currency}`;
                                    } else if (priceindicator == 3) {
                                        currencysymbol = `${currency}${currency}${currency}`;
                                    }

                                    return currencysymbol;
                                }
                                return (
                                    <View style={styles.expCardContaioner} key={Date()}>
                                        <ScrollView horizontal={true}
                          style={styles.expImgContainer} 
                       showsHorizontalScrollIndicator={false}>
                                            {item?.images?.map((elem: any) => {
                                                return (
                                                    <TouchableOpacity
                             key={elem.id} onPress={() => handleImagePress(id)}>
                                                        <Image
                                                            source={{ uri: elem.url }}
                                                            style={styles.images}
                                                            testID="locationIconId"
                                                        />
                                                    </TouchableOpacity>
                                                );
                                            })}
                                        </ScrollView>
                                        <TouchableOpacity style={styles.expTitleView}
                          onPress={() => handleViewExpCard(id)}>
                                            <Text style={styles.expTitleText}>
                           {item.title} </Text>
                                            <Text style={styles.mealTypeTitle}>
                      {item.meal_type} •
                       {CurrencyPriceIndicator(item.price_indecator, currency)}</Text>
                                            <View style={styles.ratingContainer}>
                                                <Rating
                                                    readonly={true}
                                                    type='custom'
                                                    ratingImage={IMG_CONST.STAR}
                                                    ratingColor='#F59E0B'
                                                    ratingBackgroundColor='#CBD5E1'
                                                    ratingCount={5}
                                                    startingValue={item.average_rating}
                                                    imageSize={25}
                                                    fractions={2}
                                                    style={{ paddingVertical: 1 }}
                                                />
                                                <Text style={styles.rate}>
                                                    {item.average_rating} ({item.total_reviews})
                                                </Text>
                                            </View>
                                            <View 
                      style={{ flexDirection: 'row', marginBottom: wp(4) }}>

                                                <Image
                                                    source={IMG_CONST.location}
                                                    style={styles.locationIcon}
                                                    testID="locationIconId"
                                                />
                                                <Text style={styles.rate}>
                                                    {item.city_name} 
                       {location ? `• ${milesToKilometers(item.distance, currency)}`: null}
                                                </Text>
                                            </View>
                                        </TouchableOpacity>
                                    </View>
                                )
                            }} />
                    </View>
                }}
            />

const styles = StyleSheet.create({ seeAll: { marginLeft: wp(1), alignSelf: 'center', height: wp(2.5), width: wp(2), }, images: { height: hp(15), width: hp(15), marginEnd: wp(2), borderRadius: 20 }, locationIcon: { height: wp(5), width: wp(5), }, rate: { color: '#000', marginLeft: wp(2) }, ratingContainer: { flexDirection: 'row', alignItems: "center", paddingVertical: hp(1.2) }, mealTypeTitle: { marginTop: wp(2.5), color: '#000', fontWeight: "500", fontSize: Scale(16) }, expTitleView: { marginLeft: wp(3), }, expTitleText: { color: '#000', fontWeight: '700', fontSize: Scale(20), }, expImgContainer: { marginTop: wp(3), marginLeft: wp(3), marginBottom: wp(3), zIndex: 99 }, expImgs: { backgroundColor: 'red', height: hp(15), width: hp(15), borderRadius: Scale(20) }, expCardContaioner: { marginTop: wp(2), marginRight: wp(3), backgroundColor: '#ffffff', paddingVertical: wp(1), borderRadius: Scale(20), marginBottom: wp(3), width: width - Scale(50), }, expContainer: { margin: wp(5), marginTop: wp(1.5) },

    nearByHeaderText: {
        fontSize: Scale(16),
        fontWeight: "500",
        color: "#120d26"
    },
    seeAllText: {
        fontSize: Scale(16),
        fontWeight: "500",
        color: "#747688"
    },
    expContainerHeader: {
        flexDirection: 'row',
        justifyContent: 'space-between',
        margin: wp(1)
    },
});

Upvotes: 0

Views: 87

Answers (1)

Jim Khan
Jim Khan

Reputation: 617

Using nested Flatlist is not a good solution at all. There are several built-in props inside Flatlist like ListHeaderComponent and ListFooterComponent we can pass our custom component inside it. And inside our component we can use a Flatlist as well.

Here is an example where you can use Vertical and Horizontal scroll at the same time.

const YourComponent = () => {
  //// & flatlist function for Order list ///

  const renderItemFunction = ({ item, index }) => {
    return (
      <YourCustomeComponet
        title={item.clientName}
        status={item.status}
        date={item.date}
        document={item.numDocuments}
        billStatus={item.paymentStatus}
        userName={item.agentName}
      />
    );
  };

  //// & flatlist HeaderComponent function///

  const listHeaderComponent = () => {
    return (
      <>
        <FlatList
          data={StatusData}
          ref={flatListRef}
          horizontal={true}
          keyExtractor={(item) => item.id}
          horizontal={true}
          showsHorizontalScrollIndicator={false}
          renderItem={renderItemList}
        />
      </>
    );
  };
  // const listFooterComponent = () => {
  //   return (
  //     <>
  //       <FlatList
  //         data={StatusData}
  //         ref={flatListRef}
  //         horizontal={true}
  //         keyExtractor={(item) => item.id}
  //         horizontal={true}
  //         showsHorizontalScrollIndicator={false}
  //         renderItem={renderItemList}
  //       />
  //     </>
  //   );
  // };
  return (
    <>
      <FlatList
        ListHeaderComponent={listHeaderComponent}
        ListHeaderComponentStyle={styles.headerComponent}
        data={yourData}
        contentContainerStyle={{ alignItems: "center" }}
        showsVerticalScrollIndicator={false}
        keyExtractor={(item) => item.id}
        renderItem={renderItemFunction}
        // You can use ListFooterComponent as well
        // ListFooterComponent={listFooterComponent}
        // ListFooterComponentStyle={styles.footerComponent}
      />
    </>
  );
};

const styles = StyleSheet.create({
  headerComponent: {},
});
export default YourComponent;

Upvotes: 0

Related Questions