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

Unable to change width when the screen oriantation change #754

Open
AlenToma opened this issue Jan 3, 2023 · 2 comments
Open

Unable to change width when the screen oriantation change #754

AlenToma opened this issue Jan 3, 2023 · 2 comments

Comments

@AlenToma
Copy link

AlenToma commented Jan 3, 2023

Hi I am having trouble to change item width when the screen change.

I can see that width change but somehow it is not applied to the item or maybe the item gets cached somehow.

This is the custom component I created

import {
  RecyclerListView,
  LayoutProvider,
  DataProvider,
} from 'recyclerlistview/dist/reactnative';

import {
  Dimensions,
  StyleSheet,
  ViewStyle,
  StyleProp,
  RefreshControl
} from 'react-native';
import React, { useState, useEffect, useRef, useContext } from 'react';
import { Text, View, TouchableOpacity } from '.'
import { ThemeContext } from './theme/ThemeProvider';
import AppContext from '../context/AppContext';

export type RenderItem = (type: any, item: any, index: any, productWidth: number) => JSX.Element;
export type ItemPress = (item: any, index: number) => void;

export interface IttemListProps {
  scrollToOffset: (x: number, y: number, animate?: boolean) => void;
  forceRerender(): void;
  scrollToItem(data: any, animate?: boolean): void;
  scrollToIndex: (index: number, animate?: boolean) => void;
  scrollToEnd: (animate?: boolean) => void;
  forceRerender: () => void;
}

export type Seperator = { x_name: "Seperator", content: string }

const ItemList = ({
  items,
  renderItem,
  onItemPress,
  onItemLongPress,
  onRefresh,
  seperator,
  onEndReached,
  itemHeight,
  columnPerRaw,
  onIni,
  selectedItem,
  onScroll,
  style,
  isHorizontal,
  contentContainerStyle,
  activeOpacity,
  initialoffsetY,
  nestedScrollEnabled,
  ignoreMargin,
  updators
}: {
  items: any[];
  renderItem: RenderItem;
  onItemPress?: ItemPress;
  onItemLongPress?: ItemPress;
  onRefresh?: () => Promise<void>;
  seperator?: Boolean;
  onEndReached?: Function;
  itemHeight?: number;
  columnPerRaw?: number;
  onIni?: (componenet: IttemListProps) => void;
  selectedItem?: any;
  onScroll?: (nativeEvent: any, offsetX: number, offsetY: number) => any;
  style?: StyleProp<ViewStyle>,
  contentContainerStyle?: StyleProp<ViewStyle>,
  isHorizontal?: boolean,
  activeOpacity?: number;
  initialoffsetY?: number;
  nestedScrollEnabled?: boolean;
  ignoreMargin?: boolean,
  updators?: any[]
}) => {
  const columnPer = () => {
    return (columnPerRaw ?? 1);
  }

  const globalContext = useContext(AppContext);
  const recyclerListViewRef = useRef<IttemListProps>();
  const [loading, setLoading] = useState(false)
  const [containerWidth, setContainerWidth] = useState(0)
  const [loadingSize, setloadingSize] = useState(0)
  const themeContext = useContext(ThemeContext)

  const [dataSource, setDataSource] = useState(
    new DataProvider((r1, r2) => {
      return r1 !== r2;
    }).cloneWithRows(items),
  );
  const ItemWidth = () => {
    return containerWidth || globalContext.windowDimension.width;
  }

  const calProductWidth = () => {
    return (ItemWidth() / columnPer());
  }

  const [initialOffset, setInitialOffset] = useState(initialoffsetY ?? 0);
  const [productWidth, setProductWidth] = useState(calProductWidth())
  const init = useRef(false);
  const userDrag = useRef(false);
  const endReashedTimer = useRef(undefined as any)
  const updateTimer = useRef(undefined as any)
  const layoutProvider = useRef(new LayoutProvider(
    (index) => {
      return 0;
    },
    (type, dim) => {
      dim.width = (ItemWidth() / columnPer());
      dim.height = itemHeight ?? 30;
    },
  ));

  // layoutProvider.current.shouldRefreshWithAnchoring = false;


  // when items update create new provider
  useEffect(() => {
    clearTimeout(endReashedTimer.current)
    if (items && items.length > 0 && init.current) {
      setDataSource(
        new DataProvider((r1, r2) => {
          return r1 !== r2;
        }).cloneWithRows(items),
      );
    }
  }, [items, updators]);



  useEffect(() => {
    init.current = true;
    return () => {
      clearTimeout(endReashedTimer.current)
      clearTimeout(updateTimer.current)
      init.current = false;
    }
  }, [])

  useEffect(() => {
    if (itemHeight && selectedItem) {
      setInitialOffset(items.findIndex((x) => x == selectedItem) * itemHeight);
      recyclerListViewRef.current?.forceRerender();
    }
  }, [selectedItem,]);

  const update =()=> {
    clearTimeout( updateTimer.current)
    updateTimer.current = setTimeout(() => {
      if (recyclerListViewRef.current) {
        recyclerListViewRef.current.forceRerender()
      }
    }, 10);
 
  }

  if (updators)
    useEffect(() => {
      update();
    }, updators)


  useEffect(() => {
    update();
  }, [productWidth])


  useEffect(() => {
    setProductWidth(calProductWidth());
  }, [columnPerRaw, containerWidth])



  const handleListEnd = () => {
    if (onEndReached) onEndReached();
  };
  const itemGetter = (type: any, item: any, index: any, extendedState: any) => {
    const width = columnPerRaw && columnPerRaw > 1 ? productWidth - 5 : containerWidth;
    return (
      <View key={index} style={[styles.container, { width: width, borderBottomColor: "#242529", borderBottomWidth: seperator === true ? 1 : 0 }]}>
        <TouchableOpacity
          incBackGround={false}  activeOpacity={activeOpacity ?? 0.5} onLongPress={() => onItemLongPress ? onItemLongPress(item, index) : null} onPress={onItemPress ? () => onItemPress(item, index) : undefined}>
          {renderItem(type, item, index, width)}
        </TouchableOpacity>
      </View>
    );
  };

  const scrollProps = {
    nestedScrollEnabled: nestedScrollEnabled,
    onScrollBeginDrag: () => {
      userDrag.current = true
    }
  } as any;

  if (onRefresh)
    scrollProps.refreshControl = (
      <RefreshControl
        refreshing={loading}
        onRefresh={async () => {
          setLoading(true);
          await onRefresh();
          setLoading(false);
        }}
      />
    )

  const getViewWidth = () => {
    if (columnPer() <= 1)
      return ItemWidth()
    return ((productWidth) * Math.floor(columnPer()));
  }
  return (
    <View style={[styles.listContainer, style, { alignItems: "center", width: "100%" }]} onLayout={(e) => {
      setContainerWidth(e.nativeEvent.layout.width);
    }}>
      {
        containerWidth > 0 && productWidth > 0 ? (
          <RecyclerListView
            suppressBoundedSizeException={true}
            disableRecycling={false}
            contentContainerStyle={[contentContainerStyle, styles.containers, { width: getViewWidth() }]}
            ref={(c: any) => {
              recyclerListViewRef.current = c;
              if (onIni) onIni(c);
            }}
            scrollViewProps={scrollProps}
            isHorizontal={isHorizontal}
            onScroll={(event: any, x: any, y: any) => {
              if (!initialOffset)
                setInitialOffset(y + (itemHeight ?? 100));
              if (onScroll)
                return onScroll(event, x, y);
            }}
            initialOffset={initialOffset}
            rowRenderer={itemGetter}
            dataProvider={dataSource}
            layoutProvider={layoutProvider.current}
            useWindowScroll={true}
            onEndReached={() => {
              clearTimeout(endReashedTimer.current)
              endReashedTimer.current = setTimeout(async () => {
                clearTimeout(endReashedTimer.current)
                if (userDrag.current)
                  await handleListEnd();
                clearTimeout(endReashedTimer.current)
              }, 500);

            }}
            onEndReachedThreshold={0.2}
            canChangeSize={true}
            renderFooter={() => {
              return <View style={{ height: itemHeight || 100 }}></View>
            }}
          />
        ) : null
      }
    </View>
  );
};

export default ItemList;

const styles = StyleSheet.create({
  container: {
    justifyContent: 'space-around',
    flex: 1,
    margin: 2,
    overflow: "hidden",
  },

  containers: {
    justifyContent: "space-between",
    flexGrow: 1,
    padding: 0,
    margin: 0
  },

  listContainer: {
    flex: 1,
    minHeight: 10,
    minWidth: 10,
  },
});

and here is how I call it

      {state.data && state.data.length > 0 ? (
        <ItemList
          isHorizontal={false}
          itemHeight={75}
          seperator={true}
          onItemPress={(item, index) => itemClick(item)}
          items={state.data ?? []}
          renderItem={(type: any, item: any, index: any, width: any) => renderItem(type, item, index, width)}
          onEndReached={() => {
            console.log("enReached")
            if (state.currentParser.searchPagination && !state.endResult)
              state.effectTrigger++;
          }}
        />
      ) : null}
@AlenToma
Copy link
Author

AlenToma commented Jan 3, 2023

Ok was able to fix this by creating new LayoutProvider each time the size change.

as calProductWidth somehow return the old value instead of the updated one.

this is a bug in my opinion as each time i create new LayoutProvider the scroll gets misset upp a little which I could live with

  useEffect(() => {
    layoutProvider.current = new LayoutProvider(
      (index) => {
        return 0;
      },
      (type, dim, index) => {
        dim.width = calProductWidth()
        dim.height = itemHeight ?? 30;
      },
    );
  }, [productWidth, containerWidth])

@OmarJay1
Copy link

I had a similar problem and I fixed it by adding a variable height style to the RowRenderer. I update the height with a global variable, which isn't very nice, but I have only 1 copy of the list in my app.

      Dimensions.addEventListener('change', () => {

        this.setState({dataProvider: this.state.dataProvider.cloneWithRows(this.props.data)});        

       g_width = Dimensions.get('screen').width;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants