React Native:渲染无限数量的页面(双向滑动)

HBS*_*Kan 8 arrays android carousel react-native react-native-android

人们如何实现无限数量的页面供您动态滑动?

细节

如果某个应用程序呈现了一天的页面,您可以在前一天向右滑动,在第二天向左滑动.

例如,FitNotes应用程序无缝地执行此操作: FitNotes app日视图

向右/向左滑动与按下按钮5/6相同.并显示已呈现的页面.同时,也会渲染现在相邻日期的新页面.

最初,我认为这是你使用旋转木马做的事情,例如,使用react-native-snap-carousel库.我想象下面的例子,但使用状态变量而不是图像数组渲染页面.

来自react-native-snap-carousel库的示例轮播

所以,如果我想渲染一个日期在顶部的页面,我会有一个数组作为状态的一部分,例如:

carouselElements: [ '2019/01/21', '2019/01/22', '2019/01/23']
Run Code Online (Sandbox Code Playgroud)

加入下面的旋转木马,我会得到三个页面,每个页面都显示在顶部.

<Carousel
    ref={(c) => { this._carousel = c; }}
    data={this.props.carouselElements}
    renderItem={this.renderDay}
    sliderWidth={sliderWidth}
    itemWidth={sliderWidth}
    enableSnap 
    firstItem={1}
    initialNumToRender={3}
    maxToRenderPerBatch={3}
    onBeforeSnapToItem={(index) => this.changeEvent(index)}
    useScrollView/>
Run Code Online (Sandbox Code Playgroud)

问题1:阵列无限增长

你可以Day X提前两天开始并渲染相邻的.如果我向左滑动,您可以访问Day X+1并连接Day X+2到数组的末尾并渲染那一天.

该数组变为: [ 'Day X-1', 'Day X', 'Day X+1', 'Day X+2']

为了提高性能,我可以在3天的窗口内继续检查索引,只渲染选定的日期和相邻的两天.但是数组会无限增长,你的代码最多也是O(n).

问题2:索引

a)预先安排要素:

您可以从,Day X然后向右滑动.你现在正在展示Day X-1.您添加Day X-2到数组的开头并渲染它以准备向右滑动第二次.问题是你在索引0添加的元素你的系统是指向索引0的状态,当它从改变Day X-1Day X-2,现在这样的页面显示Day X-2代替.

也就是说,当您向右滑动一天时,不是向后移动,而是每次滑动都会移回2天.

b)删除元素

如果我删除一个元素以保持数组较小,一切都会移动,但索引保持不变.索引现在指向与数组中的预期元素不同的元素,这在可以更正索引之前反映在呈现的页面中.

因此,我的问题是: 人们如何通过页面滑动无限制地实现动态页面呈现?似乎很多应用程序都有它,我找不到任何人谈论它.


编辑

编辑1:添加图像并附带编辑以更好地解释我的问题.

编辑2:我有一个使用react-native-swiper的工作实现,它基本上需要一个庞大的数组,并且只渲染紧邻显示页面的批量幻灯片.

<Swiper style={styles.wrapper} 
          showsButtons={false}
          index={currentDateIndex}
          loadMinimal={true}
          loadMinimalSize={1}
          showsPagination={false}
          loop={false}
          onIndexChanged={(index) => dispatch(changeSelectedDayByIndex(index))}
         >
          {dates.map((item) => 
              this.renderDay(item)
            )
          }
</Swiper>
Run Code Online (Sandbox Code Playgroud)

但是,该dates.map命令在启动时会造成很大的性能损失.

编辑3:slice在映射之前使用日期数组上的命令似乎不是一个选项,因为我将在现有状态转换期间进行渲染.

dio*_*sgg 7

这个解决方案是基于react-native-swiper你提到的.这是一个棘手的解决方案,如果正确完成缓存可以工作.它基于以下假设:

  • 给定ID,您可以导出ID + 1和ID-1.(这对日期有效)
  • 您只能向左或向右滚动1帧(查看).

我们的想法是在一个包装器组件周围<Swiper>保存一个状态数组,其中包含3个ID:current,left和right.

state = {
  pages: ["2", "3", "4"],
  key: 1
}
Run Code Online (Sandbox Code Playgroud)

向左或向右滑动时,您可以导出下一个或前三个ID并进行呼叫setState.该render方法将调用本地缓存信息以获取此3个ID的视图属性并呈现新屏幕.该<Swiper>元素总是指向index={1}初始PARAM,并保持这种方式.

const cache = {
  "0": "zero",
  "1": "one",
  "2": "two",
  "3": "three",
  "4": "four",
  "5": "five",
  "6": "six",
  "7": "seven",
  "8": "eight",
  "9": "nine",
  "10": "ten"
}

renderItem(item, idx) {
    const itemInt = parseInt(item)
    const style = itemInt % 2 == 0 ? styles.slide1 : styles.slide2
    return (
      <View style={style} key={idx}>
        <Text style={styles.text}>{cache[item]}</Text>
      </View>
    )
  }
Run Code Online (Sandbox Code Playgroud)

但是,当您滑动时,它会将当前索引设置为2或0.因此,为了使其始终指向索引1(再次,因为您已移动并重新加载),您必须强制<Swiper>元素重新加载.您可以通过将其键属性设置为始终更改的状态变量来实现.这是棘手的部分.

onPageChanged(idx) {
    if (idx == 2) {
                                                 //deriving ID+1
      const newPages = this.state.pages.map(i => (parseInt(i)+1).toString())
      this.setState({pages: newPages, key: ((this.state.key+1)%2) })
    } else if (idx == 0) {
                                                 //deriving ID-1
      const newPages = this.state.pages.map(i => (parseInt(i)-1).toString())
      this.setState({pages: newPages, key: ((this.state.key+1)%2) })
    }
  }

render() {
    return (
      <Swiper
        index={1}
        key={this.state.key}
        style={styles.wrapper}
        loop={false}
        showsPagination={false}
        onIndexChanged={(index) => this.onPageChanged(index)}>
        {this.state.pages.map((item, idx) => this.renderItem(item, idx))}
      </Swiper>
    );
  }
Run Code Online (Sandbox Code Playgroud)

除此之外,您必须确保始终为您的ID提供足够的缓存信息.如果缓存访问接近结束,请确保请求新数据并从另一个方向删除一些缓存数据.

这里有一个引擎收录的App.js和GitHub的项目,以便您可以测试的整体思路.

在此输入图像描述