主题:React Native 中的视频平面列表。(普通视频 / YouTube 视频)
任何一个都将根据阵列数据同时显示。所以这将是一个包含两种类型视频的长平面列表。
有时由于性能问题,许多 onPress 事件不起作用
大部分问题:
- 从底部滚动到顶部时应用程序崩溃
- 性能很差
以上两个是需要解决的主要问题。有没有办法解决这些问题?
我可以尝试哪些解决方案来提高Flatlist
性能并解决 Video Flatlist 崩溃问题?
下面是我在App.js中的代码
import React from "react";
import {
StyleSheet,
Text,
View,
SafeAreaView,
FlatList,
TouchableWithoutFeedback,
Dimensions
} from "react-native";
import Video from "react-native-video";
import ProgressBar from "react-native-progress/Bar";
import YouTube from 'react-native-youtube';
import LightVideo from "./sample.mp4";
import Icon from "react-native-vector-icons/FontAwesome";
// console.disableYellowBox = true;
function secondsToTime(time) {
return ~~(time / 60) + ":" + (time % 60 < 10 ? "0" : "") + time % 60;
}
const { width } = Dimensions.get("window");
const height = width * 0.5625;
const list = [
{
'type': 'YouTube'
},
{
'type': 'Normal'
},
{
'type': 'YouTube'
},
{
'type': 'Normal'
},
{
'type': 'Normal'
},
];
export default class RNVideo extends React.PureComponent {
state = {
video: [],
duration: [0, 0, 0, 0, 0],
progress: [0, 0, 0, 0, 0]
};
constructor(props) {
super(props);
this.player = [];
}
componentDidMount() {
this.progress_state();
this.duration_state();
this.video_pause_state(false);
}
play_pause_button = (index) => {
if (this.state.progress >= 1) {
this.player[index].seek(0);
}
var statevisible = this.state.video;
statevisible[index] = !statevisible[index];
this.setState({
video: statevisible
});
this.forceUpdate();
};
progress_bar_touch(e, index) {
const position = e.nativeEvent.locationX;
const progress = (position / 250) * this.state.duration[index];
this.player[index].seek(progress);
};
handleProgress(progress, index) {
var statevisible = this.state.progress;
statevisible[index] = progress.currentTime / this.state.duration[index];
this.setState({
progress: statevisible
});
this.forceUpdate();
};
handleLoad(meta, index) {
var statevisible = this.state.duration;
statevisible[index] = meta.duration;
this.setState({
duration: statevisible
});
this.forceUpdate();
};
onViewableItemsChanged = async ({ viewableItems }) => {
this.video_pause_state(true);
if (viewableItems != '' && viewableItems != null) {
var indexvalue = viewableItems[0]['index'];
var statevisible = this.state.video;
statevisible[indexvalue] = !statevisible[indexvalue];
this.setState({
video: statevisible
});
this.forceUpdate();
}
}
// shouldComponentUpdate() {
// return false
// }
video_pause_state(value) {
var statevisible = [];
for (var i = 0; i < list.length; i++) {
statevisible[i] = value;
}
this.setState({
video: statevisible
});
}
progress_state() {
var statevisible = [];
for (var i = 0; i < list.length; i++) {
statevisible[i] = 0;
}
this.setState({
progress: statevisible
});
}
duration_state() {
var statevisible = [];
for (var i = 0; i < list.length; i++) {
statevisible[i] = 0;
}
this.setState({
duration: statevisible
});
}
video_end(index) {
var statevisible1 = this.state.duration;
statevisible1[index] = 0;
var statevisible2 = this.state.progress;
statevisible2[index] = 0;
this.setState({
duration: statevisible1,
progress: statevisible2
});
this.play_pause_button(index);
}
keyExtractor = (item, index) => index.toString()
renderItem = ({ item, index }) => (
<>
{item.type != 'YouTube' ?
<>
<View style={styles.container}>
<View>
<Video
paused={this.state.video[index]}
muted={this.state.video[index]}
source={LightVideo}
// controls={true}
// repeat={true}
style={styles.videos}
resizeMode="cover"
onLoad={(meta) => this.handleLoad(meta, index)}
onProgress={(progress) => this.handleProgress(progress, index)}
onEnd={() => this.video_end(index)}
ref={(ref) => {
this.player[index] = ref
}}
/>
<View style={styles.controls}>
<TouchableWithoutFeedback onPress={(event) => this.play_pause_button(index)}>
<Icon name={!this.state.video[index] ? "pause" : "play"} size={30} color="#FFF" />
</TouchableWithoutFeedback>
<TouchableWithoutFeedback onPress={(event) => this.progress_bar_touch(event, index, this)}>
<View>
<ProgressBar
progress={this.state.progress[index]}
color="#FFF"
unfilledColor="rgba(255,255,255,.5)"
borderColor="#FFF"
width={230}
height={20}
/>
</View>
</TouchableWithoutFeedback>
<Text style={styles.duration}>
{secondsToTime(Math.floor(this.state.progress[index] * this.state.duration[index]))}
</Text>
</View>
</View>
</View>
</>
:
<>
<View style={{ marginTop: 50 }}>
<YouTube
apiKey="YOUR_API_KEY"
videoId="YOUR_YOUTUBE_VIDEO_ID_FROM_URL"
play={this.state.video[index]}
style={styles.videos}
/>
</View>
</>
}
</>
)
render() {
return (
<>
<SafeAreaView style={{ flex: 1 }}>
<FlatList
keyExtractor={this.keyExtractor}
data={list}
renderItem={this.renderItem}
extraData={this.state}
onViewableItemsChanged={this.onViewableItemsChanged}
removeClippedSubviews={true}
maxToRenderPerBatch={3}
initialNumToRender={3}
legacyImplementation={true}
/>
</SafeAreaView>
</>
);
}
}
const wid = "95%";
const styles = StyleSheet.create({
container: {
flex: 1,
marginBottom: 60,
marginTop: 60,
},
controls: {
backgroundColor: "rgba(0, 0, 0, 0.5)",
height: 48,
left: 0,
bottom: 0,
right: 0,
position: "absolute",
flexDirection: "row",
alignItems: "center",
justifyContent: "space-around",
width: wid,
margin: 8,
borderBottomLeftRadius: 10,
borderBottomRightRadius: 10,
paddingHorizontal: 10,
},
mainButton: {
marginRight: 15,
},
duration: {
color: "#FFF",
marginLeft: 15,
},
videos: {
width: wid,
backgroundColor: '#ccc',
borderRadius: 10,
overflow: 'hidden',
margin: 8,
height
},
});
更新
我想出了这个最终的解决方案。但无法进行自动播放。需要这方面的想法。
import React from 'react';
import { View, StyleSheet, SafeAreaView } from 'react-native';
import YouTube from 'react-native-youtube';
import { OptimizedFlatList } from 'react-native-optimized-flatlist'
import VideoPlayer from 'react-native-video-player';
const list = [
{
'type': 'Normal'
},
{
'type': 'YouTube'
},
{
'type': 'Normal'
},
{
'type': 'Normal'
},
{
'type': 'YouTube'
},
{
'type': 'Normal'
},
{
'type': 'Normal'
},
{
'type': 'Normal'
},
];
export default class App extends React.PureComponent {
constructor() {
super();
this.player = [];
this.state = {
video: { width: undefined, height: undefined, duration: undefined },
thumbnailUrl: undefined,
videoUrl: undefined,
};
}
keyExtractor = (item, index) => index.toString()
renderItem = ({ item, index }) => (
<>
{item.type != 'YouTube' ?
<>
<View style={styles.videos}>
<VideoPlayer
// autoplay
// pauseOnPress
video={{ uri: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4', type: 'mp4' }}
resizeMode={'cover'}
ref={r => this.player[index] = r}
/>
</View>
</>
:
<>
<View style={{ marginTop: 50 }}>
<YouTube
apiKey="YOUR_API_KEY"
videoId="3NQRhE772b0"
style={{...styles.videos,...styles.videos1}}
/>
</View>
</>
}
</>
)
onViewableItemsChanged = async ({ viewableItems }) => {
if (viewableItems != '' && viewableItems != null) {
var indexvalue = viewableItems[0]['index'];
indexvalue++;
if (indexvalue != 1) {
if (!this.player[indexvalue].state.isPlaying) {
this.player[indexvalue].pause();
} else {
this.player[indexvalue].resume();
}
}
}
}
render() {
return (
<>
<SafeAreaView style={{ flex: 1 }}>
<OptimizedFlatList
keyExtractor={this.keyExtractor}
data={list}
renderItem={this.renderItem}
removeClippedSubviews={true}
onViewableItemsChanged={this.onViewableItemsChanged}
/>
</SafeAreaView>
</>
);
}
}
const styles = StyleSheet.create({
videos: {
width: "95%",
backgroundColor: '#ccc',
borderRadius: 10,
overflow: 'hidden',
margin: 10,
marginBottom: 20,
marginTop: 20
},
videos1: {
height: 250
}
});