对本机搜索做出反应并滚动以点击

react native search and scroll to hit

我需要一些帮助来实现搜索和滚动以在 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',
  },
});

如能提供入门帮助,我们将不胜感激。

我的猜测是:

您可以先绑定 <ScrollView/>ref

// 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

所述函数可以使用 try catch 语句找到 ref 等于 this.state.text 的边缘情况下的优雅失败。

如果找到;可以使用 measure()

检索目标 xy 偏移量 然后可以调用

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)
  }

}

步骤

  1. 记住每个项目的位置onLayout
  2. scrollTo() 文本输入时的位置,仅当找到项目时。

代码

const styles = StyleSheet.create({
    textinput: {
        borderBottomColor: 'purple',
        textAlign: 'center',
        borderBottomWidth: 2,
        height: 40,
        marginTop: 20,
    },
    text: {
        textAlign: 'center',
        fontSize: 16,
        margin: 10,
    } 
});



export class App extends Component {
    data = [];
    datapos = {};
    scrollref = null;
    constructor(props) {
        super(props);
        /// make 100s example data
        for (var i =0; i<100; ++i)
            this.data.push(i);

        this.state = {
            inputvalue: '0'
        }
    }

    render() {
        return (
            <View style={{flex: 1}}>
                <TextInput style={styles.textinput}
                    value={this.state.inputvalue}
                    onChangeText={(text) => {
                        this.setState({inputvalue: text});
                        let y = this.datapos[+text];
                        y !== undefined && this.scrollref.scrollTo({ y, animated: true });
                    }}
                />
                <ScrollView
                    ref={(ref) => this.scrollref = ref}
                    >
                    {
                        this.data.map( (data) => (
                            <Text style={styles.text}
                                key={data}
                                onLayout={(layout) => this.datapos[data] = layout.nativeEvent.layout.y}
                                >{data}</Text>
                        ))
                    }
                </ScrollView>
            </View>
        )
    }
}

结果:

首先,我强烈建议您使用 FlatList 而不是 ScrollView。这有几个原因:

  1. FlatList 与 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,你需要知道,数据是作为数组添加到dataprop中的(我添加了一个100个数字的数组),以及方式它被渲染为 FlatList 作为 renderItemprop(我添加了与您相同样式的文本)。

此外,请注意您不需要将 ref 传递给 <Text>,因为 FlatList 已经知道它包含的项目。您只需要向 FlatList 本身添加一个引用:

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

现在当你想要制作和滚动时,你可以简单地调用FlatListscrollToIndex方法,例如写一个方法叫做scrollHandler:

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

请注意,flatListRef 是分配给 FlatList 的 ref 的名称。

现在,当你想执行滚动动作时,你可以简单地调用这个方法。例如,将您的文本输入修改为:

<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)}
/>