はじめに
こちらの記事は、React Native の FlatListでカルーセルを実装する備忘録です.
動作のイメージはこのような感じです.
環境はほぼデフォルトですので省略します. スライドショーの画像はUnsplashからお借りしました.
Version情報
- expo: ~47.0.9
- React Native: 0.70.5
各コンポーネントの作成
最初に表示するスライドショーのファイルを作成します. TypeScriptプロジェクトなのでイImageの型定義用にImageSourcePropType
をimportしています.
slide.ts
import { ImageSourcePropType } from 'react-native'
export interface ISlide {
id: string,
title: string,
description: string,
image: ImageSourcePropType
}
const slides: ISlide[] = [
{
id: '1',
title: 'beef',
description: 'grilled beef on the plate',
image: require('../assets/beef.jpg')
},
{
id: '2',
title: 'chicken',
description: 'roasted chicken on the plate',
image: require('../assets/chicken.jpg')
},
{
id: '3',
title: 'fish',
description: 'pan fried fish on the plate',
image: require('../assets/fish.jpg')
},
{
id: '4',
title: 'lamb',
description: 'roasted lamb on the plate',
image: require('../assets/lamb.jpg')
},
{
id: '5',
title: 'pasta',
description: 'carbonara pasta on the plate',
image: require('../assets/pasta.jpg')
}
];
export default slides;
次は、カルーセルのコンポーネントです.
まとめると次のようになります.
Onboarding.tsx
import {
StyleSheet,
View,
Image,
useWindowDimensions,
FlatList,
ListRenderItemInfo,
Animated,
ImageSourcePropType,
ViewToken
} from 'react-native'
import React, { useState, useRef, SetStateAction } from 'react'
import slides, { ISlide } from './slide'
const Onboarding = () => {
const [currentIndex, setCurrentIndex] = useState<number>(0);
const scrollX = useRef(new Animated.Value(0)).current;
const slidesRef = useRef(null);
const { width } = useWindowDimensions();
const Item = ({ item }: { item: ImageSourcePropType }) => {
return (
<View style={[styles.container, { width }]}>
<Image
source={item}
style={[styles.image, { width, resizeMode: 'contain' }]}
/>
</View>
);
};
const _renderItem = (listRenderItemInfo: ListRenderItemInfo<ISlide>) => {
return <Item item={listRenderItemInfo.item.image} />;
}
const viewableItemsChanged = useRef(({ viewableItems }: {viewableItems: any}) => {
setCurrentIndex(viewableItems[0])
}).current;
const viewConfig = useRef({ viewAreaCoveragePercentThreshold: 50 }).current;
return (
<View style={styles.container}>
<FlatList
data={slides}
renderItem={_renderItem}
keyExtractor={item => item.id}
horizontal
showsHorizontalScrollIndicator
pagingEnabled
bounces={false}
onScroll={Animated.event([{ nativeEvent: { contentOffset: { x: scrollX } } }], {
useNativeDriver: false,
})}
scrollEventThrottle={32}
onViewableItemsChanged={viewableItemsChanged}
viewabilityConfig={viewConfig}
ref={slidesRef}
/>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
image: {
flex: 1,
backgroundColor: 'white',
zIndex: 1,
justifyContent: 'center'
}
});
export default Onboarding;
そしてOnboardingコンポーネントをApp.tsxに入れます.
App.tsx
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, SafeAreaView, Platform } from 'react-native';
import Onboarding from './components/Onboarding';
export default function App() {
return (
<SafeAreaView style={styles.container}>
<Onboarding />
<StatusBar style="auto" />
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
},
});
以上です. 最後までご覧いただきありがとうございます.
参考情報
この記事では下記の動画を参考にしました.