Как заставить родительский вид сохранять размер во время рендеринга дочернего элемента?

#reactjs #react-native

#reactjs #react-native

Вопрос:

У меня есть список просмотров с видео внутри. Каждый раз, когда загружается видео, требуется секунда, в течение которой представление контейнера имеет размер 0. Когда видео загружается, вид «всплывает», выталкивая все в списке вниз и создавая некрасивый, ошеломляющий эффект. Когда я прокручиваю, я выгружаю видео, которые больше не видны, но из-за эффекта «всплывания» это приводит к тому, что представления родительского контейнера возвращаются к размеру 0, создавая эффект обратного перемещения.

Возможно ли, чтобы представление контейнера сохраняло информацию о высоте даже после отключения дочернего видео?

Подробности реализации: я использую react-native-inview, чтобы выяснить, отображается ли видео на экране в данный момент. Если нет, я заменяю его пустым компонентом представления. При следующем обновлении видеокомпонент будет отключен.

 <InView onChange={(isVisible) => {
                setIsInView(isVisible);
            }}>
    <MyVideo visible={isVisible} />
</InView>
  

MyVideo.js

 import Video from 'react-native-video'
...
class Video extends React.Component {
    state = {
        vHeight: 0,
        vWeight: 0,
        maxWidth: Dimensions.get('window').width,
        maxHeight: Dimensions.get('window').height,
        muted: true,
        paused: false,
    };
render() { 
if (this.props.visible) {
return <Video
    muted={this.props.muted}
    paused={this.props.paused}
    repeat={true}
    source={{
        uri: this.props.data
            ? this.props.data.video
            : this.props.source.uri,
    }} // Can be a URL or a local file.
    ref={(ref) => {
        this.player = ref;
    }}
    // Rescale video on load
    style={{height: this.state.vHeight, width: this.state.vWidth}}
    onLoad={(response) => {
        this.setState({muted: true});
        const {height: vidHeight, width: vidWidth} = response.naturalSize;
        if (vidWidth > vidHeight || this.props.maxWidth) {
            const heightScaled =
                vidHeight *
                ((this.props.maxWidth || this.state.maxWidth) / vidWidth);
            this.setState({vHeight: heightScaled, vWidth: '100%'});
        } else {
            const widthScaled = vidWidth * (this.state.maxHeight / vidHeight);
            this.setState({
                vWidth: widthScaled,
                vHeight: this.state.maxHeight,
            });
        }
    }} />

} else {
            return (
                <View
                    style={{
                        height: this.state.vHeight,
                        width: this.state.vWidth,
                    }}
                />
            );
        }}
};
  

Комментарии:

1. Можете ли вы показать, как вы размонтируете видео, как вы их монтируете и какова конфигурация компонента списка и видеокомпонентов? Кроме того, есть ли у вас метаданные видео, доступные в элементах списка? Если это так, вы можете просто отобразить некоторое пространство-заполнитель для каждого элемента.

2. Я использую react-native-video, и у него нет метаданных размера до обратного вызова onLoad. Поэтому я не знаю, насколько большим должно быть пространство-заполнитель, пока не будет загружено видео. Есть ли еще способ реализовать подобное пространство-заполнитель?

3. Вы не можете отобразить правильную высоту, не зная правильной высоты. Я бы рекомендовал сохранить эти метаданные в элементах списка или предварительно выбрать их из вашего хранилища объектов. Я не могу помочь с размонтированием, не видя всего кода, за исключением того, что вам, вероятно, не нужно делать это вручную.

4. Не могли бы вы пояснить, что вы подразумеваете под «сохранением в элементах списка»? Насколько я знаю, состояние использования сбрасывается при каждом размонтировании

Ответ №1:

Вот пример настройки FlatList для использования с видео (взято отсюда https://medium.com/@jenshandersson/react-native-optimized-flatlist-of-videos-bb048cb696db )

 //config for registering flatlist item viewability
viewabilityConfig = {
  waitForInteraction: false,
  minimumViewTime: 250,
  viewAreaCoveragePercentThreshold: 50
};

<FlatList
  style={{ flex: 1 }}
  data={[{ url: "", meta: { height: 4, width: 3 } }]}
  renderItem={this._renderItem}
  keyExtractor={(item) => item.id}
  onViewableItemsChanged={this._onViewableItemsChanged}
  initialNumToRender={3}
  maxToRenderPerBatch={3}
  windowSize={5}
  getItemLayout={(_data, index) => ({
    length: cellHeight,
    offset: cellHeight * index,
    index,
  })}
  viewabilityConfig={viewabilityConfig}
  removeClippedSubviews={true}
  ListFooterComponent={
    <TouchableOpacity onPress={this.loadItems}>
      <Text style={{ padding: 30 }}>Load more</Text>
    </TouchableOpacity>
  }
/>
  

Они используются onViewableItemsChanged для вызова unload , но используют другую реализацию видео. Для react-native-video я бы переключился на плакат или уменьшенное изображение, чтобы в памяти не было слишком много приостановленных видео.