الرد الأصلي: تقديم قائمة قابلة للسحب وقابلة للضبط

من الصعب اليوم مفاجأة أي شخص لديه القدرة على تمرير عناصر القائمة في تطبيقات الهاتف المحمول. كان أحد تطبيقات التفاعل الأصلي لدينا مثل هذه الوظيفة ، ولكن في الآونة الأخيرة كانت هناك حاجة لتوسيعها مع القدرة على سحب وإسقاط عناصر القائمة. وبما أن عملية البحث عن حل كلفتني قدرًا معينًا من الخلايا العصبية ، فقد قررت تقديم مقالة قصيرة من أجل توفير وقت ثمين للأجيال القادمة.



في تطبيقنا ، استخدمنا حزمة react-native-swipe-list-view القائمة القابلة للتمرير السريع. كان الفكر الأول هو اتخاذ بعض الحزم مع وظيفة drag'n'drop وعبور القنفذ بثعبان.

أعطى البحث على شبكة الإنترنت ثلاثة مرشحين: react-native-draggable-list react-native-sortable-list react-native-draggable-list react-native-sortable-list react-native-draggable-flatlist react-native-sortable-list react-native-draggable-flatlist react-native-sortable-list react-native-draggable-flatlist .

باستخدام الحزمة الأولى ، لم يكن من الممكن تشغيل المثال المرفق (ولكن ليس لي فقط ، تتم الإشارة إلى المشكلة المقابلة في المشكلات ).

اضطررت إلى العبث بالحزمة الثانية ، لكنني تمكنت من إنشاء قائمة قابلة للسحب والقابلة للتبديل. ومع ذلك ، لم يكن مصدر إلهام النتيجة - كان العنصر يومض بشكل خجل: وميض إعادة الرسم أو سقوط عناصر أبعد من القائمة أو حتى اختفائها. أصبح من الواضح أنه في هذا الشكل لا يمكن استخدامه.

في البداية ، تصرفت الحزمة الأخيرة أيضًا كسيدة متقلبة ، ولكن اتضح بعد ذلك أنني لم أكن أعرف كيف أطبخها. بعد أن حصلت على مفتاح قلب هذه "السيدة" ، تمكنت من تحقيق نتيجة مقبولة.

في مشروعنا ، كانت هناك قائمة قابلة للضبط تحتاج إلى ربط السحب والإفلات ، ولكن من الناحية العملية ، من الأفضل أن تبدأ من الحافة الأخرى: قم أولاً بوضع قائمة قابلة للسحب ثم أضف القدرة على التمرير السريع.

من المفترض أن يعرف القراء كيفية إنشاء مشروع رد فعل أصلي ، لذلك دعونا نركز على إنشاء القائمة التي نحتاج إليها. المثال الذي تمت مناقشته أدناه هو رمز TypeScript.

صنع قائمة قابلة للسحب


لذلك ، لنبدأ بتثبيت الحزمة:

 yarn add react-native-draggable-flatlist 

نحن نستورد الوحدات اللازمة:

 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' 

هنا DraggableFlatList هو مكون من الحزمة المثبتة التي تقوم بتنفيذ ListItem السحب والإفلات ، ListItem هو fakeData لعرض عنصر قائمة (سيتم تقديم الرمز أدناه) ، fakeData هو ملف json يحتوي على بيانات مزيفة - في هذه الحالة ، مجموعة من الكائنات من النموذج:

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

في تطبيق حقيقي ، من المرجح أن تأتي هذه البيانات إلى المكون الخاص بك من الدعائم أو سيتم تنزيلها من الشبكة ، ولكن في حالتنا سوف ندير القليل من الدم.

نظرًا لاستخدام TypeScript في هذا المثال ، فإننا نصف بعض الكيانات:

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

يخبرنا نوع Language بالمجالات التي ستحتوي عليها عناصر القائمة.

في هذا المثال ، لن نحصل على أي شيء من الدعائم ، لذلك واجهة AppProps تافهة ، وفي القصة سنقوم بتخزين مجموعة من كائنات Language ، المشار إليها في واجهة AppState .

نظرًا لأن رمز المكون ليس كبيرًا جدًا ، فسأقدمه بالكامل:

رمز مكون التطبيق
 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} /> ) } } 


يتم onMoveEnd الأسلوب onMoveEnd عند نقل العنصر. في هذه الحالة ، نحتاج إلى وضع القائمة بترتيب جديد للعناصر في الولاية ، لذلك نسميها this.setState .

renderItem طريقة renderItem عنصر قائمة وتقبل كائنًا من النوع RenderItemInfo <Language>. يتضمن هذا الكائن الحقول التالية:

  • item - تم تمرير العنصر التالي للصفيف كبيانات إلى القائمة ،
  • move و moveEnd هي وظائف تسمى عند نقل عنصر قائمة ، يوفر مكون DraggableFlatList هذه الوظائف ،
  • isActive هو حقل منطقي يحدد ما إذا كان العنصر قابلاً للسحب حاليًا أم لا.

مكون عرض عنصر القائمة ، في الواقع ، هو TouchableOpacity ، والذي move عند الضغط عليه لفترة طويلة ، وعندما move ، move moveEnd .

رمز مكون 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 


يتم نقل أنماط جميع المكونات إلى ملفات منفصلة ولا يتم تقديمها هنا ، ولكن يمكن عرضها في المستودع .

النتيجة الناتجة:



إضافة القدرة على انتقاد


حسنًا ، لقد تعاملنا بنجاح مع الجزء الأول ، انتقلنا إلى الجزء الثاني من رقص مارليزون.

لإضافة القدرة على تمرير عناصر القائمة ، نستخدم حزمة react-native-swipe-list-view .

للبدء ، دعنا نثبته:

 yarn add react-native-swipe-list-view 

تحتوي هذه الحزمة على مكون SwipeRow ، والذي يجب أن يتضمن مكونين:

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

لاحظ أن العرض الأول يتم رسمه تحت الثانية.

دعنا نغير رمز مكون ListItem .

رمز مكون 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 


أولاً ، أضفنا مكون SwipeRow مع خاصية SwipeRow ، التي تحدد المسافة التي يمكن تمرير العنصر إليها.

ثانياً ، قمنا بتحريك SwipeRow بنا داخل SwipeRow بإضافة طريقة عرض ، والتي سيتم رسمها تحت هذا الزر.

داخل طريقة العرض هذه ، يتم رسم صورة لتحديد ما إذا كانت اللغة مفضلة. عند النقر فوقها ، يجب عكس القيمة ، وحيث أن البيانات في المكون الأصلي ، فأنت بحاجة إلى رمي رد اتصال هنا يقوم بتنفيذ هذا الإجراء.

قم بإجراء التغييرات الضرورية على المكون الأصل:

رمز مكون التطبيق
 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 


مصادر المشروع على جيثب .

والنتيجة معروضة أدناه:

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


All Articles