Bereaksi Asli: buat daftar yang bisa diseret & digesek

Hari ini sulit untuk mengejutkan siapa pun dengan kemampuan untuk menggesek item daftar di aplikasi seluler. Salah satu aplikasi asli-reaksi kami juga memiliki fungsi seperti itu, tetapi baru-baru ini ada kebutuhan untuk mengembangkannya dengan kemampuan untuk menarik dan melepaskan item daftar. Dan karena proses menemukan solusi menghabiskan sel-sel saraf dalam jumlah tertentu, saya memutuskan untuk mengajukan artikel pendek untuk menghemat waktu berharga bagi generasi mendatang.



Dalam aplikasi kami, kami menggunakan paket react-native-swipe-list-view untuk membuat daftar swipeable. Pikiran pertama adalah mengambil beberapa paket dengan fungsionalitas drag'n'drop dan menyeberang landak dengan seekor ular.

Pencarian di internet memberi tiga kandidat: react-native-draggable-list , react-native-sortable-list dan react-native-draggable-flatlist .

Menggunakan paket pertama, itu tidak mungkin untuk menjalankan bahkan contoh terlampir (namun, tidak hanya bagi saya, masalah yang sesuai ditunjukkan dalam masalah ).

Saya harus mengotak-atik paket kedua, tetapi saya berhasil membuat daftar yang dapat diseret & digesek. Namun, hasilnya tidak diilhami - komponennya tanpa berkedip berkedip: berkedip redraw, elemen jatuh jauh di luar daftar, atau bahkan hilangnya mereka. Menjadi jelas bahwa dalam bentuk ini tidak dapat digunakan.

Pada awalnya, paket terakhir juga berperilaku seperti wanita yang berubah-ubah, tetapi kemudian ternyata saya tidak tahu cara memasaknya. Setelah mengambil kunci ke jantung "wanita" ini, saya berhasil mencapai hasil yang dapat diterima.

Di proyek kami, ada daftar gesek yang harus Anda kencangkan tarik dan lepas, tetapi dalam praktiknya lebih baik mulai dari ujung yang lain: pertama buat daftar yang dapat diseret lalu tambahkan kemampuan untuk menggesek.

Pembaca seharusnya tahu cara membuat proyek yang bereaksi asli, jadi mari kita fokus membuat daftar yang kita butuhkan. Contoh yang dibahas di bawah ini adalah kode TypeScript.

Membuat daftar yang dapat diseret


Jadi, mari kita mulai dengan menginstal paket:

 yarn add react-native-draggable-flatlist 

Kami mengimpor modul yang diperlukan:

 import React, { Component } from 'react' import { View } from 'react-native' import styles from './styles' import DraggableFlatList, { RenderItemInfo, OnMoveEndInfo } from 'react-native-draggable-flatlist' import ListItem from './components/ListItem' import fakeData from './fakeData.json' 

Di sini DraggableFlatList adalah komponen dari paket yang diinstal yang mengimplementasikan fungsi drag and drop, ListItem adalah komponen kami untuk menampilkan item daftar (kode akan disajikan di bawah ini), fakeData adalah file json yang berisi data palsu - dalam hal ini, array objek berupa:

 {"id": 0, "name": "JavaScript", "favorite": false} 

Dalam aplikasi nyata, data ini kemungkinan besar akan datang ke komponen Anda dari alat peraga atau akan diunduh dari jaringan, tetapi dalam kasus kami, kami akan mengelola dengan sedikit darah.

Karena TypeScript digunakan dalam contoh ini, kami menjelaskan beberapa entitas:

 type Language = { id: number, name: string, favorite: boolean, } interface AppProps {} interface AppState { data: Array<Language> } 

Jenis Language memberi tahu kita bidang mana yang akan dimiliki item daftar.

Dalam contoh ini, kita tidak akan mendapatkan apa pun dari alat peraga, sehingga antarmuka AppProps sepele, dan dalam cerita ini kita akan menyimpan berbagai objek Language , yang ditunjukkan dalam antarmuka AppState .

Karena kode komponen tidak terlalu besar, saya akan memberikannya secara keseluruhan:

Kode komponen aplikasi
 class App extends Component<AppProps, AppState> { constructor(props: AppProps) { super(props) this.state = { data: fakeData, } } onMoveEnd = ({ data }: OnMoveEndInfo<Language>) => { this.setState({ data: data ? [...data] : [] }) } render() { return ( <View style={styles.root}> <DraggableFlatList data={this.state.data} renderItem={this.renderItem} keyExtractor={(item) => item.id.toString()} scrollPercent={5} onMoveEnd={this.onMoveEnd} /> </View> ) } renderItem = ({ item, move, moveEnd, isActive }: RenderItemInfo<Language>) => { return ( <ListItem name={item.name} move={move} moveEnd={moveEnd} isActive={isActive} /> ) } } 


Metode onMoveEnd dipanggil saat item dipindahkan. Dalam hal ini, kita perlu meletakkan daftar dengan tatanan elemen baru di negara, jadi kita memanggil metode this.setState .

Metode renderItem item daftar dan menerima objek bertipe RenderItemInfo <Language>. Objek ini mencakup bidang-bidang berikut:

  • item - elemen berikutnya dari array yang dilewatkan sebagai data ke daftar,
  • move and moveEnd adalah fungsi yang dipanggil saat item daftar dipindahkan, komponen DraggableFlatList menyediakan fungsi-fungsi ini,
  • isActive adalah bidang boolean yang menentukan apakah item saat ini dapat diseret.

Komponen untuk menampilkan item daftar, pada kenyataannya, TouchableOpacity , yang, dengan pers lama, panggilan move , dan ketika dirilis, itu moveEnd .

Kode komponen ListItem
 import React from 'react' import { Text, TouchableOpacity } from 'react-native' import styles from './styles' interface ListItemProps { name: string, move: () => void, moveEnd: () => void, isActive: boolean, } const ListItem = ({ name, move, moveEnd, isActive }: ListItemProps) => { return ( <TouchableOpacity style={[styles.root, isActive && styles.active]} onLongPress={move} onPressOut={moveEnd} > <Text style={styles.text}>{name}</Text> </TouchableOpacity> ) } export default ListItem 


Gaya untuk semua komponen dipindahkan ke file yang terpisah dan tidak diberikan di sini, tetapi mereka dapat dilihat di repositori .

Hasil yang dihasilkan:



Tambahkan kemampuan untuk menggesek


Nah, kami berhasil mengatasi bagian pertama, kami melanjutkan ke bagian kedua dari balet Marlezon.

Untuk menambahkan kemampuan untuk menggesek item daftar, kami menggunakan paket react-native-swipe-list-view .

Untuk memulai, mari kita instal:

 yarn add react-native-swipe-list-view 

Paket ini berisi komponen SwipeRow , yang, menurut dokumentasi, harus mencakup dua komponen:

 <SwipeRow> <View style={hiddenRowStyle} /> <View style={visibleRowStyle} /> </SwipeRow> 

Perhatikan bahwa Tampilan pertama diambil di bawah yang kedua.

Mari kita ubah kode komponen ListItem .

Kode komponen ListItem
 import React from 'react' import { Text, TouchableOpacity, View, Image } from 'react-native' import { SwipeRow } from 'react-native-swipe-list-view' import { Language } from '../../App' import styles from './styles' const heart = require('./icons8-heart-24.png') const filledHeart = require('./icons8-heart-24-filled.png') interface ListItemProps { item: Language, move: () => void, moveEnd: () => void, isActive: boolean, onHeartPress: () => void, } const ListItem = ({ item, move, moveEnd, isActive, onHeartPress }: ListItemProps) => { return ( <SwipeRow rightOpenValue={-180}> <View style={styles.hidden}> <TouchableOpacity onPress={onHeartPress}> <Image source={item.favorite ? filledHeart : heart} /> </TouchableOpacity> </View> <TouchableOpacity activeOpacity={1} style={[styles.root, isActive && styles.active]} onLongPress={move} onPressOut={moveEnd} > <Text style={styles.text}>{item.name}</Text> </TouchableOpacity> </SwipeRow> ) } export default ListItem 


Pertama, kami menambahkan komponen SwipeRow dengan properti SwipeRow , yang menentukan jarak di mana elemen dapat digesek.

Kedua, kami memindahkan TouchableOpacity kami di dalam SwipeRow dan menambahkan Tampilan, yang akan digambar di bawah tombol ini.

Di dalam Tampilan ini, gambar diambil untuk menentukan apakah bahasa itu favorit. Ketika Anda mengkliknya, nilainya harus dibalik, dan karena data ada di komponen induk, Anda perlu melakukan panggilan balik di sini yang melakukan tindakan ini.

Buat perubahan yang diperlukan untuk komponen induk:

Kode komponen aplikasi
 import React, { Component } from 'react' import { View } from 'react-native' import styles from './styles' import DraggableFlatList, { RenderItemInfo, OnMoveEndInfo } from 'react-native-draggable-flatlist' import ListItem from './components/ListItem' import fakeData from './fakeData.json' export type Language = { id: number, name: string, favorite: boolean, } interface AppProps {} interface AppState { data: Array<Language> } class App extends Component<AppProps, AppState> { constructor(props: AppProps) { super(props) this.state = { data: fakeData, } } onMoveEnd = ({ data }: OnMoveEndInfo<Language>) => { this.setState({ data: data ? [...data] : [] }) } toggleFavorite = (value: Language) => { const data = this.state.data.map(item => ( item.id !== value.id ? item : { ...item, favorite: !item.favorite } )) this.setState({ data }) } render() { return ( <View style={styles.root}> <DraggableFlatList data={this.state.data} renderItem={this.renderItem} keyExtractor={(item) => item.id.toString()} scrollPercent={5} onMoveEnd={this.onMoveEnd} /> </View> ) } renderItem = ({ item, move, moveEnd, isActive }: RenderItemInfo<Language>) => { return ( <ListItem item={item} move={move} moveEnd={moveEnd} isActive={isActive} onHeartPress={() => this.toggleFavorite(item)} /> ) } } export default App 


Sumber proyek di GitHub .

Hasilnya disajikan di bawah ini:

Source: https://habr.com/ru/post/id460567/


All Articles