Реагировать на собственный горизонтальный пейджинг FlatList TouchableOpacity scrollToIndex бесконечный цикл - PullRequest
0 голосов
/ 27 апреля 2018

Я вижу проблему с использованием кнопки TouchableOpacity для управления горизонтальной прокруткой FlatList. Если я активирую Remote Debugging, все работает нормально, но если я отключаю отладку, тач не возвращается и пользовательский интерфейс приложения не отвечает.

Я пытаюсь реализовать горизонтальную прокрутку FlatList, которая по сути является пошаговой wizard пользовательским интерфейсом.

FlatList (подкачка включена, горизонтальная) имеет от 3 до 7 элементов в массиве данных, и у меня есть кнопки prev и next, реализованные с компонентами TouchableOpacity в отдельном представлении внизу экрана. У меня есть пользовательский компонент View, который будет представлять содержимое каждого шага (на данный момент он имеет одну текстовую метку).

При нажатии на кнопку «предыдущий» или «предыдущий» следует перейти к следующему индексу в FlatList. Используя что-то вроде:

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

Я создал проблему в репозитории React Native GitHub. Кто-нибудь видел такое поведение? Любые известные обходные пути?

Я вижу это на 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):

Мое изображение

Я ценю любую помощь или мысли по этому поводу! Спасибо !!

Обновление / примечание: если я удаляю FlatList, кнопки TouchableOpacity будут работать нормально, поэтому определенно может возникнуть какая-то несовместимость между FlatList и другими элементами Touchable на одном экране.

Отредактировал приведенный выше код, чтобы предоставить очень простой пример этой проблемы. Если я запускаю с использованием отладчика, все хорошо, но если нет, то нажатие кнопок «Предыдущий» или «Следующий» TouchableOpacity никогда не возвращается, и пользовательский интерфейс зависает.

Обновление: если я что-то изменю, чтобы данные моего FlatList и реквизиты currentList не были частью this.state, я могу увеличить индекс прокрутки с помощью нажатия TouchableOpacity. Проблема заключается в том, что я хотел бы обновить состояние, чтобы в режиме просмотра отображалась информация о текущем шаге (например, «Шаг x из y»).

Обновление состояния в функциях _nextStep () или _previousStep () не должно вызывать условие бесконечного цикла, верно? Я думал, что FlatList будет перерисовывать только тогда, когда изменятся реквизиты данных или extraData. Как я уже говорил ранее, если я запускаю в отладчике, я не зацикливаюсь.

Эта версия, кажется, работает - я также сделал чистую, встроенную в 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
        }
      )
    }
  }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...