我看到使用 TouchableOpacity 'button'来控制 FlatList 的水平滚动的问题 . 如果我激活 Remote Debugging ,一切正常,但如果我关闭调试,触摸不会回来,应用程序UI没有响应 .

我正在尝试实现一个水平滚动 FlatList ,这本质上是一步一步的 wizard ui .

FlatList (分页启用,水平)在数据数组中有3到7个项目,我在屏幕底部的单独视图中使用 TouchableOpacity 组件实现 prevnext 按钮 . 我有一个自定义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
        };
      });
    }
  }

这里's a screen shot of what I' m building(带有文本'location'的灰色区域是水平 FlatList 中的全角项目):

My image

我感谢任何帮助或想法!谢谢!!

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

编辑了上面的代码,提供了一个非常'bare-bones'这个问题的例子 . 如果我使用调试器运行,一切都很好,但如果我不这样做,则点击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
        }
      )
    }
  }