Zeinab_Ns
Zeinab_Ns

Reputation: 305

How to make Horizontal SectionList RIGHT to LEFT Scroll react-native

I want to make an online shop, I need a Horizontal section List in react native, contains my products. here is my code. please help me to make it right to left scrolling.clothes is an array of objects contains my product's details.

    export default class MySectionList extends Component{
        render(){
            return(
               <SectionList
                   sections={Clothes} 
                   horizontal={true}
                   showsHorizontalScrollIndicator={false}
                   renderItem={({item})=>(
                       <View>
                           <Image source={{uri:"item.image",width:'65%',height:200}}/>
                           <Text>{item.name}</Text>
                           <Text>{item.price}</Text>
                       </View>
                  )}
                  renderSectionHeader={({section})=>(
                       <Text>{section.title}</Text>)}
              />
       )
    }
}

this sectionList scrolls from left to right and I need another one scrolling from left to right.

Upvotes: 4

Views: 5035

Answers (4)

Ali Khajehpour
Ali Khajehpour

Reputation: 134

Using I18nManager.forceRTL or inverted alone is not enough to make FlatList fully RTL, because if you have fewer items than the screen size, the list will start from the left side instead of the right. check out this issue

I found a solution for it, and it works on React Native 0.75.2, but this issue may be fixed in future react native updates.


import React, {useEffect, useRef, useState} from 'react';
import {FlatList, I18nManager} from 'react-native';

/**
 * HorizontalRTLSupportFlatList
 *
 * This component is a custom wrapper around React Native's FlatList to add support
 * for Right-to-Left (RTL) layouts when rendering horizontal lists. It automatically
 * handles reversing the scroll direction and item order in RTL mode while maintaining
 * the correct visual order of list items. Additionally, it includes logic to manage
 * scrolling behavior in large screens and to handle potential scroll failures.
 *
 * Why this component was created:
 * - React Native's FlatList does not provide native RTL scrolling for horizontal lists.
 * - This component ensures correct scrolling direction and item order in RTL layouts.
 * - It solves the need for a reusable RTL-friendly horizontal FlatList component.
 *
 * Key Features:
 * - Automatically flips the FlatList's horizontal scrolling in RTL mode by reversing the data and using the `inverted` prop.
 * - Reverses the data array to display items in the correct visual order for RTL layouts.
 * - Scrolls to the last item in RTL mode (or the first item in LTR mode) after the layout is complete.
 * - Adjusts the scroll offset to center the selected item for large screens.
 * - Handles potential `scrollToIndex` failures by using `onScrollToIndexFailed` to retry scrolling after a small delay.
 *
 * Scroll Behavior:
 * - Uses the `inverted` prop to flip the scrolling direction in RTL mode without the need for a `scaleX` transformation.
 * - Scrolls to the last item in RTL mode once the layout is complete and retries scrolling on failure.
 * - Adjusts the scroll offset on large screens for better centering of items.
 */

const HorizontalRTLSupportFlatList = ({renderItem, data, ...props}) => {
  const flatListRef = useRef(null); // Reference for accessing FlatList methods like scrollToIndex
  const [isLayoutComplete, setIsLayoutComplete] = useState(false); // Tracks whether the FlatList has completed layout
  const [isScrollToIndexFailed, setScrollToIndexFailed] = useState(false); // Tracks if scrollToIndex has failed

  // Reverse the data if RTL mode is active to ensure the correct visual order of items.
  const processedData = I18nManager.isRTL ? [...data].reverse() : data;

  useEffect(() => {
    // Scroll to the last item in RTL mode after the layout is complete
    if (I18nManager.isRTL && isLayoutComplete && flatListRef.current && processedData.length > 0) {
      flatListRef.current.scrollToIndex({index: processedData.length - 1, animated: false});
    }
  }, [isLayoutComplete, isScrollToIndexFailed, processedData]);

  return (
    <FlatList
      ref={flatListRef} // Ref to programmatically control FlatList
      horizontal // Specifies horizontal list layout
      inverted={I18nManager.isRTL} // Inverts scrolling in RTL mode
      data={processedData} // Use processed (reversed) data for correct RTL order
      {...props} // Spread other props like keyExtractor, extraData, etc.
      renderItem={renderItem} // Function to render each item in the list
      onLayout={() => setIsLayoutComplete(true)} // Trigger layout completion callback
      onScrollToIndexFailed={info => {
        // Handle scrollToIndex failure and retry after a short delay
        const wait = new Promise(resolve => setTimeout(resolve, 200));
        wait.then(() => {
          setScrollToIndexFailed(true);
        });
      }}
    />
  );
};

export default HorizontalRTLSupportFlatList;

Upvotes: 0

Babu
Babu

Reputation: 5220

I had a similar demand for the right-to-left functionality. I used horizontal FlatList (in 2022) with an inverted property.

   <FlatList
        horizontal
        data={diaryWeeksAll}
        inverted
        getItemLayout={(_data, index) => ({ length: width, offset: width * index, index })}
       ...

See documentation: https://reactnative.dev/docs/flatlist#inverted

Upvotes: 0

Ali SabziNezhad
Ali SabziNezhad

Reputation: 3118

I solve this by adding some styles. Unfortunately, I18NManager could not solve my problem so I used transform style and for all section list I applied transform: [{ scaleX: -1 }] and because of items inside sectionlist will be reversed, I applied this style again for item wrapper. something like this:

    render(){
            return(
               <SectionList
                   sections={Clothes} 
                   horizontal={true}
                   style={{ transform: [{ scaleX: -1 }] }}
                   showsHorizontalScrollIndicator={false}
                   renderItem={({item})=>(
                       <View style={{ transform: [{ scaleX: -1 }] }}>
                           <Image source={{uri:"item.image",width:'65%',height:200}}/>
                           <Text>{item.name}</Text>
                           <Text>{item.price}</Text>
                       </View>
                  )}
                  renderSectionHeader={({section})=>(
                       <Text>{section.title}</Text>)}
              />
           )
       }
    }

This is a hacky way but I did not find another solution for my problem.

I hope this can help you

Upvotes: 7

Matin Zadeh Dolatabad
Matin Zadeh Dolatabad

Reputation: 1017

If your app language is right to left please set app support to use rtl with

I18NManager.allowRTL(true) 
I18NManager.forceRTL(true)  

to make section list or flat list scroll from right to left, Otherwise this cannot happen. There are another ways to solve this issue but it's not systematic! Like use inverted prop or direction style.

Upvotes: 1

Related Questions