ریاکتجیاس - سرچ و اسکرول در ریاکت نیتیو برای رسیدن به هدف


من به کمی کمک برای پیادهسازی جستجو و اسکرول برای دسترسی در React Native نیاز دارم. تحقیقات زیادی انجام دادم و به چند بنبست رسیدم (چند نمونه refs پیدا کردم که نتوانستم کارشان کنم).

تلاش کردم این قطعه کد را به عنوان شروع بسازم:

https://snack.expo.io/@norfeldt/searching-and-scroll-to

import React, { Component } from 'react';
import { Text, View, ScrollView, TextInput, StyleSheet } from 'react-native';

export default class App extends Component {

  state = {
    text: '41'
  }

  render() {
    return (
      <View style={styles.container}>

      <TextInput
        style={{height: 60, borderColor: 'gray', borderWidth: 1, borderRadius: 10, margin: 5, padding:30, color: 'black', }}
        onChangeText={(text) => this.setState({text})}
        value={this.state.text}
      />

      <ScrollView >

          {[...Array(100)].map((_, i) => {return <Text style={styles.paragraph} key={i}>{i}</Text>})}

      </ScrollView>

      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    paddingTop: 10,
    backgroundColor: '#ecf0f1',
  },
  paragraph: {
    margin: 10,
    fontSize: 18,
    fontWeight: 'bold',
    textAlign: 'center',
    color: '#34495e',
  },
});

هر کمکی برای شروع قدردانی خواهد شد.

پاسخ شماره ۱

حدس من این است:

میتوانید با بایند کردن یک ref از <ScrollView/> خود شروع کنید.

// ScrollView Ref.
<ScrollView ref={(ref) => this['ScrollView'] = ref}>
  ...
</ScrollView>

و هر یک از اجزای <Text/> شما (با index).

// Text Refs.
<Text ref={(ref) => this[i] = ref} style={styles.paragraph} key={i}>{i}</Text>

شما سپس میتوانستید یک submit() function تنظیم کنید.

این تابع میتواند ref برابر با this.state.text را با استفاده از یک دستور try catch برای شکست خوشخیم در موارد حاشیهای پیدا کند.

اگر یافت شد؛ آفست هدف x و y میتواند با استفاده از measure() بازیابی شود

سپس میتوان scrollTo() را فراخوانی کرد تا به المان هدف پیمایش شود.

// Scroll To Query.
submit = () => {

  try {

    const { text } = this.state // Text.
    const target = this[text] // Target.

    // Locate Target.
    target.measure((framex, framey, width, height, x, y) => {

      // Scroll To Target.
      this.ScrollView.scrollTo({x, y, animated: true})
    })

  } catch (error) {

    return console.log(error)
  }

}

پاسخ شماره ۲

ابتدا، من قویاً توصیه میکنم که به جای ScrollView از FlatList استفاده کنید. دلایل چندی برای این موضوع وجود دارد:

  1. FlatList در مقایسه با ScrollView عملکرد بسیار بهینهتری دارد (در ScrollView همه آیتمها به صورت همزمان رندر میشوند، صرفنظر از اینکه آیا در صفحه نمایش قابل مشاهده هستند یا خیر)
  2. علاوه بر این، مدیریت پیمایش و آیتمهای رندر شده در FlatList بسیار سادهتر است، شما نیازی به دانستن چیزی درباره محور x و y و پیکسلها ندارید، فقط با ایندکسها کار میکنید.

به منظور داشتن یک مقایسه جامع بین این دو روش، شما میتوانید به موارد زیر نگاه کنید:

http://matthewsessions.com/2017/05/15/optimizing-list-render-performance.html

حالا برگردیم به سوال شما، همانطور که گفتم پیشنهاد میکنم از FlatList استفاده کنید، آنوقت همه چیز به سادگی یک تکه کیک خواهد بود. شما میتوانید نمونهٔ تغییر یافتهٔ اکسپو خود را در اینجا پیدا کنید:

https://snack.expo.io/HkMZS1SGz

تغییراتی که شما نیاز دارید در کد خود اعمال کنید، شامل موارد زیر است:

  1. به جای استفاده از ScrollView از FlatList استفاده کنید، پس این را تغییر دهید:

    <FlatList ref={ref => {this.flatListRef=ref;}} data={new Array(100).fill(0).map((item, index) => index)} renderItem={({ item }) => ( <Text style={styles.paragraph}> {item} </Text> )} />

اگر قبلاً با FlatList آشنا نیستید، باید بدانید که دادهها در پراپ data به صورت یک آرایه اضافه میشوند (من یک آرایه از 100 عدد اضافه کردم)، و نحوهی نمایش آن به FlatList از طریق پراپ renderItem داده میشود (من متن را با همان سبکدهی که شما استفاده کردید اضافه کردم).

علاوه بر این، توجه داشته باشید که نیازی به ارسال ref به <Text> ندارید، زیرا FlatList قبلاً از آیتمهایی که شامل آن است آگاه است. شما فقط نیاز دارید که یک ref به خود FlatList اضافه کنید:

 ref={ref => {this.flatListRef = ref;}}

حال هر زمان که بخواهید پیمایش انجام دهید، میتوانید به سادگی متد scrollToIndex از FlatList را فراخوانی کنید، به عنوان مثال متدی به نام scrollHandler بنویسید:

 // Scroll to Query
  scrollHandler = (itemIndex)=>{
    this.flatListRef.scrollToIndex({animated: true, index: itemIndex});
  }

فقط توجه داشته باشید که، flatListRef نام رفی است که به FlatList اختصاص داده شده است.

حالا، وقتی میخواهید عملیات پیمایش را انجام دهید، میتوانید به سادگی این متد را فراخوانی کنید. برای مثال، ورودی متن خود را به این صورت تغییر دهید:

<TextInput
        style={{height: 60, borderColor: 'gray', borderWidth: 1, 
                borderRadius: 10, margin: 5, padding:30, color: 'black', }}
        onChangeText={(text) => this.setState({text})}
        value={this.state.text}
        onSubmitEditing={()=>this.scrollHandler(this.state.text)}
/>