Skip to content

Commit

Permalink
chore: update example with LazyFlatList
Browse files Browse the repository at this point in the history
  • Loading branch information
johnhaup committed Oct 24, 2024
1 parent b9b0fce commit 97a8324
Show file tree
Hide file tree
Showing 8 changed files with 254 additions and 0 deletions.
4 changes: 4 additions & 0 deletions example/app/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ export default function Layout() {
name="scrollviews/vertical"
options={{ title: 'Vertical Lazy' }}
/>
<Stack.Screen
name="scrollviews/flatlist"
options={{ title: 'Lazy FlatList' }}
/>
<Stack.Screen
name="scrollviews/horizontal"
options={{ title: 'Horizontal Lazy' }}
Expand Down
2 changes: 2 additions & 0 deletions example/app/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { HorizontalCard } from '../components/cards/HorizontalCard';
import { NoLazyCard } from '../components/cards/NoLazyCard';
import { VerticalCard } from '../components/cards/VerticalCard';
import { FlatListCard } from '../components/cards/FlatListCard';

export default function App() {
const { top, bottom } = useSafeAreaInsets();
Expand All @@ -32,6 +33,7 @@ export default function App() {
</View>
<VerticalCard />
<HorizontalCard />
<FlatListCard />
<NoLazyCard />
</ScrollView>
);
Expand Down
124 changes: 124 additions & 0 deletions example/app/scrollviews/flatlist.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import React, { useCallback, useRef } from 'react';
import {
ImageSourcePropType,
ListRenderItemInfo,
StyleSheet,
Text,
TouchableOpacity,
View,
} from 'react-native';
import {
LazyFlatList,
LazyFlatListMethods,
} from 'react-native-lazy-scrollview';
import { ALBUMS, PADDING_VERTICAL } from '../../constants';
import shuffle from 'lodash/shuffle';
import { FireOnceBlock } from '../../components/blocks/FireOnceBlock';
import { ImageBlock } from '../../components/blocks/ImageBlock';
import { NoLazyChild } from '../../components/blocks/NoLazyChild';
import { Header } from '../../components/blocks/Header';

const OFFSET = -50;

type Block = ImageSourcePropType | 'no-lazy' | 'fire-once';

export default function FlatList() {
const ref = useRef<LazyFlatListMethods>(null);

const data: Block[] = shuffle(
ALBUMS.concat(shuffle(ALBUMS)).concat(shuffle(ALBUMS))
);

const renderItem = useCallback(
({ item: source, index }: ListRenderItemInfo<Block>) => {
if (source === 'no-lazy') {
return <NoLazyChild key={`no-lazy-child-${index}`} />;
}

if (source === 'fire-once') {
return (
<FireOnceBlock
key={`fire-once-child-${index}`}
percentVisibleThreshold={1}
debug
/>
);
}

return (
<ImageBlock
key={`${source.toString()}-${index}`}
source={source}
percentVisibleThreshold={1}
debug
/>
);
},
[]
);

return (
<View style={styles.scrollviewContainer}>
<LazyFlatList
ref={ref}
offset={OFFSET}
showsVerticalScrollIndicator={false}
numColumns={2}
ListHeaderComponent={Header}
data={data}
renderItem={renderItem}
debug
/>
<View style={styles.arrowsContainer}>
<TouchableOpacity
style={styles.arrowButton}
activeOpacity={0.7}
onPress={() => ref.current?.scrollToStart({ animated: true })}
>
<Text style={styles.arrow}>⬆️</Text>
</TouchableOpacity>
<TouchableOpacity
activeOpacity={0.7}
onPress={() => ref.current?.scrollToEnd({ animated: true })}
>
<Text style={styles.arrow}>⬇️</Text>
</TouchableOpacity>
</View>
</View>
);
}

const styles = StyleSheet.create({
scrollviewContainer: {
flex: 1,
backgroundColor: '#ecf0f1',
},
offsetBar: {
position: 'absolute',
bottom: OFFSET * -1 + PADDING_VERTICAL,
borderBottomWidth: 1,
borderBottomColor: 'black',
left: 0,
right: 0,
opacity: 0.7,
height: 50,
justifyContent: 'flex-end',
},
offsetText: {
color: 'white',
fontSize: 18,
fontWeight: '600',
backgroundColor: '#000',
padding: 8,
alignSelf: 'flex-start',
},
arrowsContainer: {
top: 8,
right: 8,
position: 'absolute',
justifyContent: 'center',
flexDirection: 'row',
},
arrowButton: { marginBottom: 8 },
arrow: { fontSize: 32 },
});
Binary file added example/assets/flatlist.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/assets/header.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
86 changes: 86 additions & 0 deletions example/components/blocks/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import React, { ComponentProps, useState } from 'react';

Check failure on line 1 in example/components/blocks/Header.tsx

View workflow job for this annotation

GitHub Actions / lint

'ComponentProps' is defined but never used
import {
Dimensions,
Image,
ImageSourcePropType,

Check failure on line 5 in example/components/blocks/Header.tsx

View workflow job for this annotation

GitHub Actions / lint

'ImageSourcePropType' is defined but never used
StyleSheet,
View,
} from 'react-native';
import { LazyChild } from 'react-native-lazy-scrollview';
import { SQUARE_SIZE } from '../../constants';

Check failure on line 10 in example/components/blocks/Header.tsx

View workflow job for this annotation

GitHub Actions / lint

'SQUARE_SIZE' is defined but never used
import { Skeleton } from '../loaders/Skeleton';

const SCREEN_WIDTH = Dimensions.get('window').width;

export function Header() {
const [triggered, setTriggered] = useState(false);
const [isVisible, setIsVisible] = useState(false);

const onEnterThresholdPass = () => {
setTriggered(true);
};

const onExitThresholdPass = () => {
setTriggered(false);
};

const onVisibilityEnter = () => {
setIsVisible(true);
};

const onVisibilityExit = () => {
setIsVisible(false);
};

return (
<View style={styles.container}>
<LazyChild
onEnterThresholdPass={onEnterThresholdPass}
onExitThresholdPass={onExitThresholdPass}
onVisibilityEnter={onVisibilityEnter}
onVisibilityExit={onVisibilityExit}
percentVisibleThreshold={0.5}
>
<View style={styles.contentContainer}>
<Skeleton show={!triggered}>
<Image
source={require('../../assets/header.jpg')}
style={styles.image}
/>
</Skeleton>
{!isVisible ? <View style={styles.percentTextWrapper} /> : null}
</View>
</LazyChild>
</View>
);
}

const styles = StyleSheet.create({
container: {
justifyContent: 'center',
alignItems: 'center',
alignSelf: 'center',
width: SCREEN_WIDTH,
},
contentContainer: {
width: SCREEN_WIDTH,
height: SCREEN_WIDTH * 1.25,
justifyContent: 'center',
alignItems: 'center',
},
image: {
width: SCREEN_WIDTH,
height: SCREEN_WIDTH * 1.25,
resizeMode: 'cover',
},
percentTextWrapper: {
position: 'absolute',
top: 0,
right: 0,
bottom: 0,
left: 0,
backgroundColor: 'rgba(255, 255, 255, 0.5)',
justifyContent: 'center',
alignItems: 'center',
},
});
29 changes: 29 additions & 0 deletions example/components/cards/FlatListCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React, { useEffect } from 'react';
import {
interpolate,
useAnimatedStyle,
useSharedValue,
withRepeat,
withTiming,
} from 'react-native-reanimated';
import { FLATLIST } from '../../constants';
import { Card } from './Card';

export function FlatListCard() {
const animation = useSharedValue(0);

useEffect(() => {
animation.value = withRepeat(withTiming(1, { duration: 1000 }), -1, true);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const animatedStyle = useAnimatedStyle(() => {
return {
marginRight: 16,
transform: [
{ translateY: interpolate(animation.value, [0, 1], [-20, 20]) },
],
};
});

return <Card scrollView={FLATLIST} animatedStyle={animatedStyle} />;
}
9 changes: 9 additions & 0 deletions example/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@ export const VERTICAL = {
image: require('./assets/vertical.png'),
};

export const FLATLIST = {
name: 'flatlist',
title: 'Lazy FlatList',
color: '#f8a5c2',
description:
'Less use cases than LazyScrollView, but still useful for situations where you need to measure headers or footers, or have specific cells react granularly to scroll visibility. Not recommended to wrap every item in LazyChild.',
image: require('./assets/flatlist.png'),
};

export const HORIZONTAL = {
name: 'horizontal',
title: 'Horizontal Lazy ScrollView',
Expand Down

0 comments on commit 97a8324

Please sign in to comment.