はじめに
React Native + Expo でドロップ&ドロップ可能なリスト(SortableなList)を作成する方法をご紹介します。
最初はreact-native-sortable-list
なるものを試したのですが、ライブラリ内部で古い記述があり警告が消せないので断念しました。
次にreact-native-draggable-flatlist
というライブラリを試したところ、まずまずよかったのでこのライブラリの記事を書きます。
なお、動作させるアプリは、Expo + NativeBase で土台まで作ってあるものになります。
ライブラリのインストールその前に
Expo のバージョンが 36.0.0 以上でないと、react-native-reanimated
というライブラリで警告が出てしまうので、まず Expo を 36.0.0 にアップグレードします。
$ expo upgrade
ライブラリのインストール
ライブラリのインストールですが、yarn
やnpm
ではなくexpo install
というコマンドを使うのに注意してください。おそらく、Expo 互換のバージョンをインストールするための仕組みだと思います。但し、アンインストールは、npm uninstall
を使うのがよく分かりませんが。。
以下の2つのライブラリをインストールします。
$ expo install react-native-sortable-list $ expo install react-native-reanimated
ライブラリの組み込み
Expo の画面にライブラリを組み込みます。
ほぼほぼサンプルの通りですが、関数型にしていることと、TypeScript にしているところがサンプルとの違いでしょうか。
import React, { useState } from 'react'; import { Container, Header, Title, Left, Icon, Right, Button, Body, Content, } from 'native-base'; import { TouchableOpacity, Text, SafeAreaView } from 'react-native'; import DraggableFlatList from 'react-native-draggable-flatlist'; // 表示用データ const exampleData = [...Array(20)].map((d, index) => ({ key: `item-${index}`, // For example only -- don't use index as your key! label: index, backgroundColor: `rgb(${Math.floor(Math.random() * 255)}, ${index * 5}, ${132})`, })); const HomeScreen: React.FunctionComponent = () => { const [data, setData] = useState(exampleData); const renderItem = ({ item, index, drag, isActive }) => { return ( <TouchableOpacity style={{ height: 100, backgroundColor: isActive ? 'blue' : item.backgroundColor, alignItems: 'center', justifyContent: 'center', }} onLongPress={drag} > <Text style={{ fontWeight: 'bold', color: 'white', fontSize: 32, }} > {item.label} </Text> </TouchableOpacity> ); }; return ( <Container> <Header> <Left> <Icon name="menu" /> </Button> </Left> <Body> <Title>トップ画面</Title> </Body> <Right /> </Header> <SafeAreaView style={{ flex: 1 }}> <DraggableFlatList data={data} renderItem={renderItem} keyExtractor={(item, index) => `draggable-item-${item.key}`} onDragEnd={({ data }) => setData(data)} /> </SafeAreaView> </Container> ); }; export default HomeScreen;
これを動作させると以下のようになります。
- iPhone
- Android
はまったところ
Expo をアップグレードしないとライブラリの警告がでることもはまりましたが、下記の警告がでたのにかなりはまりました。
VirtualizedLists should never be nested inside plain ScrollViews with the same orientation - use another VirtualizedList-backed container instead.
ネットでも苦戦していたようです。
解決策は以下の StackOverflow にありました。
結局のところ、ドラッグ&ドロップ可能な<FlatList>
を<ScrollView>
にネストするのがいけないようです。コンポーネントで展開されたあとに<ScrollView>
になるものも同様ですね。
おわりに
React Native + Expo でドラッグ&ドロップ可能なリストは選択肢が少ないですが、まともに動作するものがあってよかったです。