#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 я бы переключился на плакат или уменьшенное изображение, чтобы в памяти не было слишком много приостановленных видео.