React Native FlatList水平分页TouchableOpacity scrollToIndex无限循环

时间:2018-04-27 15:18:24

标签: react-native jsx react-native-flatlist

我发现使用TouchableOpacity'按钮'来控制FlatList的水平滚动时出现问题。如果我激活Remote Debugging,一切正常,但如果我关闭调试,则触摸不会回来,应用UI无响应。

我正在尝试实现水平滚动FlatList,这实际上是一步一步wizard ui。

FlatList(已启用分页,水平)数据数组中有3到7个项目,我有prevnext个按钮,单独使用TouchableOpacity个组件实现查看屏幕底部。 我有一个自定义的View组件,它将代表每个步骤的内容(目前,它只有一个Text标签)。

点击next或prev应该滚动到FlatList中的下一个索引。 使用类似的东西:

this.flatListRef.scrollToIndex({index: this.state.currentStepIndex + 1, animated: true});

我在React Native GitHub repo中创建了一个问题。有没有人见过这种行为?任何已知的工作?

我在Android和iOS上看到了这一点。 这是我的环境:

react: ^16.3.2 => 16.3.2
react-native: ^0.55.3 => 0.55.3

这是我的原始代码:

  render() {
    console.log('Render newrequestscreen', this.state, this.flatListRef)
    return (
      <SafeAreaView style={baseStyles.safeAreaDark}>
        <View style={baseStyles.swipeContainerView} >
          <Text style ={baseStyles.emptyListSubtitleText} > {this.state.flexItems.length == this.state.currentStepIndex ? 'Review & Submit' : 'Step ' + (this.state.currentStepIndex + 1) + ' of ' + (this.state.flexItems.length) }</Text>
        </View>
        <FlatList
          ref={(ref) => { this.flatListRef = ref; }}
          scrollEnabled={false}
          initialNumToRender={1}
          initialScrollIndex={0}
          refreshing={false}
          pagingEnabled={true}
          horizontal
          getItemLayout={(data, index) => (
            {length: Dimensions.get('window').width, offset: Dimensions.get('window').width * index, index}
          )}
          data={this.state.flexItems}
          showsHorizontalScrollIndicator = { false }
          decelerationRate={0}
          renderItem={({item, index}) => {
            return (
              <View style={baseStyles.swipeContainerView} pointerEvents='none' >
                <Text style ={baseStyles.emptyListSubtitleText} >{item.promptText}</Text>
              </View>
              )
            }
          }
          keyExtractor={(item) => item.type}/>
        <View style={baseStyles.swipeContainerView} >
          <View style={baseStyles.requestNavView}>
            <TouchableOpacity
              onPress={this._previousStep.bind(this)}
              style={requestComponentStyles.locationCaptureButton}>
              <Text style={requestComponentStyles.locationCaptureButtonText}>Prev Step</Text>
            </TouchableOpacity>
            <TouchableOpacity
              onPress={this._nextStep.bind(this)}
              style={requestComponentStyles.locationCaptureButton}>
              <Text style={requestComponentStyles.locationCaptureButtonText}>Next Step</Text>
            </TouchableOpacity>
          </View>
        </View>
    </SafeAreaView>
    );
  }

  _nextStep() {
    console.log('next tapped...', this.flatListRef)
    if (this.state.currentStepIndex < this.state.flexItems.length - 1) {
      this.flatListRef.scrollToIndex({index: this.state.currentStepIndex + 1, animated: true});
      this.setState(function(prevState, props) {
        return {
          currentStepIndex: prevState.currentStepIndex + 1
        };
      });
    }
  }

  _previousStep() {
    console.log('prev tapped...', this.flatListRef)
    if (this.state.currentStepIndex > 0) {
      this.flatListRef.scrollToIndex({index: this.state.currentStepIndex - 1, animated: true});
      this.setState(function(prevState, props) {
        return {
          currentStepIndex: prevState.currentStepIndex - 1
        };
      });
    }
  }

以下是我正在构建的内容的屏幕截图(文本“location”的灰色区域是水平FlatList中的全宽项目):

My image

感谢您对此有任何帮助或想法!谢谢!

更新/注意:如果我删除FlatList,TouchableOpacity按钮工作正常,所以FlatList和同一屏幕上的其他Touchable元素之间似乎存在某种不兼容性。

编辑上面的代码,提供了一个非常“简单”的问题示例。如果我使用调试器运行,一切都很好,但如果我没有,则点击Prev或Next TouchableOpacity按钮永远不会返回并且UI挂起。

更新:如果我更改了事物以使我的FlatList的数据和currentList道具不是this.state的一部分,我可以通过TouchableOpacity按下来推进滚动索引。问题是,我想更新状态,以便进度视图显示当前步骤信息(例如'步骤x的y')。

更新_nextStep()或_previousStep()函数中的状态不应该导致无限循环条件,对吧?我认为FlatList只会在data或extraData props更改时重新呈现。就像我之前说过的,如果我在调试器中运行,我就不会进入无限循环。

这个版本似乎有效 - 我也做了一个干净的,在Xcode中构建:

  constructor(props) {
    super(props)

    this.state = {
      stepIndex: 0
    }

    this.currentStepIndex = 0;

    this.nextStep = this._nextStep.bind(this);
    this.previousStep = this._previousStep.bind(this);

    this.flexItems =  [
      { promptText: 'step 1', type: 'intro' },
      { promptText: 'step 2', type: 'location' },
      { promptText: 'step 3', type: 'pickList' },
      { promptText: 'step 4', type: 'longText' },
      { promptText: 'step 5', type: 'photo' },
      { promptText: 'Review and Submit', type: 'review' }
    ];

    this.nextStep = this._nextStep.bind(this);
    this.previousStep = this._previousStep.bind(this);

    console.log('State: ', this.state);
  }

  render() {
    console.log('Render new request screen')
    return (
      <SafeAreaView style={baseStyles.safeAreaDark}>
        <View style={baseStyles.newRequestContainerView} >
        <View style={baseStyles.requestProgressView} >
          <Text style ={baseStyles.emptyListSubtitleText} > {this.flexItems.length == this.state.stepIndex ? 'Review & Submit' : 'Step ' + (this.state.stepIndex + 1) + ' of ' + (this.flexItems.length) }</Text>
        </View>
        <FlatList
          ref={(ref) => { this.flatListRef = ref; }}
          scrollEnabled={false}
          initialNumToRender={1}
          initialScrollIndex={0}
          refreshing={false}
          pagingEnabled={true}
          horizontal
          getItemLayout={(data, index) => (
            {length: Dimensions.get('window').width, offset: Dimensions.get('window').width * index, index}
          )}
          data={this.flexItems}
          showsHorizontalScrollIndicator = { false }
          decelerationRate={0}
          renderItem={({item, index}) => {
            if (item.type === 'intro') {
              return (
                <View style={baseStyles.swipeContainerView} >
                  <View style={baseStyles.swipeContentView} >
                    <Text style ={baseStyles.emptyListSubtitleText}>All About Potholes</Text>
                  </View>
                </View>
              )

            } else if (item.type === 'pickList') {
              return (
                <View style={baseStyles.swipeContainerView} >
                  <View style={baseStyles.swipeContentView} >
                    <Text style ={baseStyles.emptyListSubtitleText} >{item.promptText}</Text>
                  </View>
                </View>
              )
            } else  {
              return (
                <View style={baseStyles.swipeContainerView} >
                  <View style={baseStyles.swipeContentView} >
                    <Text style ={baseStyles.emptyListSubtitleText} >{item.promptText}</Text>
                  </View>
                </View>
              )
            }
          }}
          keyExtractor={(item) => item.type}/>
      </View>
      <View style={baseStyles.requestNavView}>
        <TouchableOpacity
          onPress={this.previousStep}
          style={requestComponentStyles.locationCaptureButton}>
          <Text style={requestComponentStyles.locationCaptureButtonText}>Prev Step</Text>
        </TouchableOpacity>
        <TouchableOpacity
          onPress={this.nextStep}
          style={requestComponentStyles.locationCaptureButton}>
          <Text style={requestComponentStyles.locationCaptureButtonText}> {this.state.stepIndex < this.flexItems.length - 1 ? 'Next Step' : 'Submit'}</Text>
        </TouchableOpacity>
      </View>

    </SafeAreaView>
    );
  }

  _nextStep() {
    console.log('next tapped...')

    if (this.currentStepIndex < this.flexItems.length - 1) {
      this.currentStepIndex = this.currentStepIndex + 1;
      this.flatListRef.scrollToIndex({index: this.currentStepIndex, animated: true});

      this.setState (
        {
          stepIndex: this.currentStepIndex
        }
      )

    } else {
      this._onDismissScreen();
    }
  }

  _previousStep () {
    console.log('prev tapped...')
    if (this.currentStepIndex > 0) {
      this.currentStepIndex = this.currentStepIndex - 1;
      this.flatListRef.scrollToIndex({index: this.currentStepIndex, animated: true});
      this.setState (
        {
          stepIndex: this.currentStepIndex
        }
      )
    }
  }

0 个答案:

没有答案