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

Horizontal #44

Merged
merged 10 commits into from
Oct 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion example/App.js

This file was deleted.

4 changes: 3 additions & 1 deletion example/app.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"expo": {
"name": "Lazy ScrollView",
"scheme": "lazyscrollview",
"slug": "example",
"version": "1.0.0",
"orientation": "portrait",
Expand All @@ -26,6 +27,7 @@
},
"web": {
"favicon": "./assets/favicon.png"
}
},
"plugins": ["expo-router"]
}
}
23 changes: 23 additions & 0 deletions example/app/_layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from 'react';
import { Stack } from 'expo-router';

export default function Layout() {
return (
<Stack
screenOptions={{ headerBackTitleVisible: false, headerTintColor: '#000' }}
>
<Stack.Screen
name="scrollviews/vertical"
options={{ title: 'Vertical Lazy' }}
/>
<Stack.Screen
name="scrollviews/horizontal"
options={{ title: 'Horizontal Lazy' }}
/>
<Stack.Screen
name="scrollviews/nocontext"
options={{ title: 'No Lazy' }}
/>
</Stack>
);
}
68 changes: 68 additions & 0 deletions example/app/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import React from 'react';
import { Stack } from 'expo-router';
import {
Dimensions,
Image,
ScrollView,
StyleSheet,
Text,
View,
} from 'react-native';
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';

export default function App() {
const { top, bottom } = useSafeAreaInsets();

return (
<ScrollView
style={styles.container}
contentContainerStyle={{ paddingTop: top, paddingBottom: bottom }}
>
<Stack.Screen options={{ headerShown: false }} />
<View style={styles.row}>
<Image source={require('../assets/lazy.png')} style={styles.image} />
<View style={styles.textContainer}>
<Text style={styles.header} numberOfLines={2}>
Lazy ScrollView Example App
</Text>
</View>
</View>
<VerticalCard />
<HorizontalCard />
<NoLazyCard />
</ScrollView>
);
}

const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#ecf0f1',
padding: 16,
},
image: {
width: Dimensions.get('window').width * 0.3,
aspectRatio: 1,
},
row: {
flexDirection: 'row',
justifyContent: 'space-between',
flex: 1,
alignItems: 'flex-end',
},
textContainer: {
flex: 1,
justifyContent: 'flex-end',
alignItems: 'flex-end',
padding: 8,
},
header: {
fontSize: 24,
fontWeight: 'bold',
lineHeight: 32,
textAlign: 'right',
},
});
79 changes: 79 additions & 0 deletions example/app/scrollviews/horizontal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import React, { useRef } from 'react';

import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import {
LazyScrollView,
LazyScrollViewMethods,
} from 'react-native-lazy-scrollview';
import { PADDING_VERTICAL } from '../../constants';
import { Blocks } from '../../components/blocks/Blocks';

const OFFSET = -50;

export default function HorizontalScrollView() {
const ref = useRef<LazyScrollViewMethods>(null);

return (
<View style={styles.scrollviewContainer}>
<LazyScrollView
ref={ref}
offset={OFFSET}
showsHorizontalScrollIndicator={false}
horizontal
>
<Blocks horizontal />
</LazyScrollView>
<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',
alignItems: 'center',
flexDirection: 'row',
},
arrowButton: {},
arrow: { fontSize: 32 },
});
21 changes: 21 additions & 0 deletions example/app/scrollviews/nocontext.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import React from 'react';
import { ScrollView, StyleSheet } from 'react-native';
import { Blocks } from '../../components/blocks/Blocks';

export default function NoContext() {
return (
<ScrollView
showsVerticalScrollIndicator={false}
style={styles.scrollviewContainer}
>
<Blocks />
</ScrollView>
);
}

const styles = StyleSheet.create({
scrollviewContainer: {
flex: 1,
backgroundColor: '#ecf0f1',
},
});
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import React, { useRef } from 'react';

import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import {
LazyScrollView,
LazyScrollViewMethods,
} from 'react-native-lazy-scrollview';
import { PADDING_VERTICAL } from '../../constants';
import { BlockColumns } from './BlockColumns';
import { Blocks } from '../../components/blocks/Blocks';

const OFFSET = -100;
const OFFSET = -50;

export function VerticalScrollView() {
export default function VerticalScrollView() {
const ref = useRef<LazyScrollViewMethods>(null);

return (
Expand All @@ -20,7 +19,7 @@ export function VerticalScrollView() {
offset={OFFSET}
showsVerticalScrollIndicator={false}
>
<BlockColumns />
<Blocks />
</LazyScrollView>
<View style={styles.arrowsContainer}>
<TouchableOpacity
Expand All @@ -37,18 +36,14 @@ export function VerticalScrollView() {
<Text style={styles.arrow}>⬇️</Text>
</TouchableOpacity>
</View>
<View style={styles.offsetBar}>
<Text style={styles.offsetText}>{`Offset: ${OFFSET}`}</Text>
</View>
</View>
);
}

const styles = StyleSheet.create({
scrollviewContainer: {
flex: 1,
paddingVertical: PADDING_VERTICAL,
backgroundColor: '#2d3436',
backgroundColor: '#ecf0f1',
},
offsetBar: {
position: 'absolute',
Expand All @@ -70,11 +65,11 @@ const styles = StyleSheet.create({
alignSelf: 'flex-start',
},
arrowsContainer: {
top: 0,
bottom: 0,
right: 0,
top: 8,
right: 8,
position: 'absolute',
justifyContent: 'center',
flexDirection: 'row',
},
arrowButton: { marginBottom: 8 },
arrow: { fontSize: 32 },
Expand Down
Binary file added example/assets/horizontal.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/lazy.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/no.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/vertical.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
88 changes: 88 additions & 0 deletions example/components/blocks/Blocks.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { chunk } from 'lodash';
import shuffle from 'lodash/shuffle';
import React, { useCallback } from 'react';
import {
Dimensions,
ImageSourcePropType,
StyleSheet,
View,
} from 'react-native';
import { ALBUMS, SQUARE_SIZE } from '../../constants';
import { FireOnceBlock } from '../blocks/FireOnceBlock';
import { ImageBlock } from '../blocks/ImageBlock';
import { NoLazyChild } from '../blocks/NoLazyChild';

export function Blocks({ horizontal }: { horizontal?: boolean }) {
const chunks = chunk(
shuffle(ALBUMS.concat(shuffle(ALBUMS)).concat(shuffle(ALBUMS))),
9
);

const renderBlock = useCallback(
(source: ImageSourcePropType | 'no-lazy' | 'fire-once', index: number) => {
if (source === 'no-lazy') {
return <NoLazyChild key={`no-lazy-child-${index}`} />;
}

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

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

const renderRow = (
column: (ImageSourcePropType | 'no-lazy' | 'fire-once')[],
index: number
) => {
return (
<View
key={`column-${index}`}
style={[
{ flexDirection: 'row' },

Check warning on line 55 in example/components/blocks/Blocks.tsx

View workflow job for this annotation

GitHub Actions / lint

Inline style: { flexDirection: 'row' }
index % 2 === 0 ? styles.offsetHorizontal : {},
]}
>
{column.map(renderBlock)}
</View>
);
};

return horizontal ? (
<View style={[{ width: Dimensions.get('window').width * 4 }]}>
{chunks.map(renderRow)}
</View>
) : (
<View style={styles.container}>
<View>{shuffle(ALBUMS).map(renderBlock)}</View>
<View>
<View style={styles.offset}>{shuffle(ALBUMS).map(renderBlock)}</View>
</View>
</View>
);
}

const styles = StyleSheet.create({
container: {
flexDirection: 'row',
},
offset: {
transform: [{ translateY: -SQUARE_SIZE / 2 }],
},
offsetHorizontal: {
transform: [{ translateX: -SQUARE_SIZE / 2 }],
},
});
Loading
Loading