react-native 短视频播放
2021-08-12 本文已影响0人
物联白菜
效果图
3661628821614_.pic.jpg缺的图片自己补
import React, {Component} from 'react';
import {View, Text, Image, TouchableOpacity, TextInput,FlatList,StyleSheet,Animated} from 'react-native'
import Util from '../common/util'
import Video from 'react-native-video';
import * as URLconstant from "../../app2/constant/URLconstant";
import MyStroage from "../../app2/common/myStroage";
//备用视频链接
// url:'http://vfx.mtime.cn/Video/2019/02/04/mp4/190204084208765161.mp4',
// url:'http://vfx.mtime.cn/Video/2019/03/19/mp4/190319212559089721.mp4',
// url:'http://vfx.mtime.cn/Video/2019/03/21/mp4/190321153853126488.mp4',
class TVideoDetail extends Component {
constructor(props) {
super(props);
this.onLoad = this.onLoad.bind(this);
this.onProgress = this.onProgress.bind(this);
this.videoError = this.videoError.bind(this);
this.onSeek = this.onSeek.bind(this);
this.page = this.props.route.params.page-1
this.state = {
video_list:[
{link:'http://vfx.mtime.cn/Video/2019/02/04/mp4/190204084208765161.mp4',id:1,duration:0.0,currentTime:0.0,paused:false}, //true暂停、false播放
{link:'http://vfx.mtime.cn/Video/2019/03/19/mp4/190319212559089721.mp4',id:2,duration:0.0,currentTime:0.0,paused:true},
{link:'http://vfx.mtime.cn/Video/2019/03/21/mp4/190321153853126488.mp4',id:3,duration:0.0,currentTime:0.0,paused:true},
],
rate: 1,
volume: 1,
muted: false,
resizeMode: 'contain',
curVideoIndex:0,
}
}
async componentDidMount() {
let userInfoDate = await MyStroage.getStorageAllDataForKey('userinfo')
if (!userInfoDate) {
this.setState({
isLogin: false,
loaded: false,
});
return
} else {
let user_id = userInfoDate.data.user_id;
// this.GET_VIDEO_LIST(user_id);
this.setState({
user_id:user_id,
isLogin:true,
})
}
}
/**数据请求start**/
//视频列表
GET_VIDEO_LIST(user_id){
console.log('this.page====',this.page,'this.props.route.params.item===',this.props.route.params.item)
try {
let datakey = [];
if (user_id != null || user_id != '') {
datakey['user_id'] = user_id;
datakey['page'] = this.page;
datakey['size'] = 5;
datakey['status'] = 1;
datakey['ifGetInfo_user'] = 1;
let url = URLconstant.VIDEO_LIST
Util.get(url, datakey, (datas)=>{
console.warn('观看视频列表===',datas,)
let data = datas.data.list
data.map((item,id)=>{
item.duration = 0.0
item.currentTime = 0.0
id === 0 ? item.paused = false : item.paused = true
})
if(datas.status===0){
if(this.page === 1){
this.setState({
video_list:data
})
}else{
Array.prototype.push.apply(this.state.video_list, data);
}
}
}, this.errorcallback.bind(this));
}
} catch (e) {
console.warn('请求失败===',e)
}
}
errorcallback(e){
console.warn('请求失败3====',e)
}
/**数据请求end**/
onLoad(data) {
console.log('onLoad===',data)
let video_list = this.state.video_list
let curVideoIndex = this.state.curVideoIndex
video_list[curVideoIndex].duration = data.duration
this.setState({
video_list
})
}
onProgress(data) {
let video_list = this.state.video_list
let curVideoIndex = this.state.curVideoIndex
video_list[curVideoIndex].currentTime = data.currentTime
this.setState({
video_list:video_list
})
}
onSeek(data) {
let video_list = this.state.video_list
let curVideoIndex = this.state.curVideoIndex
video_list[curVideoIndex].currentTime = data.currentTime
console.log('onSeek===',data.currentTime,video_list[curVideoIndex].currentTime)
this.setState({
video_list:video_list
})
}
//暂时未完成
onMoveSeek(){
let video_list = this.state.video_list
let curVideoIndex = this.state.curVideoIndex
video_list[curVideoIndex].player.seek(3)
// this.player.seek(20);
}
onPaused(){
let video_list = this.state.video_list
let curVideoIndex = this.state.curVideoIndex
video_list[curVideoIndex].paused = !video_list[curVideoIndex].paused
this.setState({
video_list
})
}
videoError(e) {
console.warn('onLoadErr===',e)
}
_onPress(id){
switch (id) {
case 0 :
console.warn('查看详情')
break;
case 1 :
console.warn('点赞')
break;
case 2 :
console.warn('评论')
break;
case 3 :
console.warn('转发')
break;
}
}
//listview上拉触发
async onEndReached() {
console.log('到底了执行')
}
getCurrentTimePercentage() {
let video_list = this.state.video_list
let curVideoIndex = this.state.curVideoIndex
let CurrentTimePercentage
if(video_list[curVideoIndex].currentTime>0){
CurrentTimePercentage = parseFloat(video_list[curVideoIndex].currentTime) / parseFloat(video_list[curVideoIndex].duration);
}else{
CurrentTimePercentage = 0
}
return CurrentTimePercentage
};
renderItem = ({ item, index, onPress , onPress2}) => {
return (
<View activeOpacity={1} onPress={()=>this.onPaused()} style={{height: Util.size.height,backgroundColor:'#000',position:'relative'}}>
<Video
source={{uri: item.link}} // Can be a URL or a local file.
ref={(ref) => {
item.player = ref
}} // Store reference
style={[Styles.fullScreen,]}
// poster={"https://baconmockup.com/300/200/"} //加载视频时要显示的图像值:带有海报URL的字符串,例如“https://baconmockup.com/300/200/”
posterResizeMode={'cover'} //确定当帧与原始视频尺寸不匹配时如何调整海报图像的大小。contain、center、cover、none、repeat、stretch
rate={this.state.rate} //视频播放的速率。 0.0 - 暂停播放 1.0 - 正常速率播放
paused={item.paused} //控制播放器是否暂停。
playWhenInactive={true} //在通知或控制中心位于视频前面时是否应继续播放媒体。
volume={this.state.volume} //调整音量
muted={this.state.muted} //控制音频是否静音。
resizeMode={this.state.resizeMode} //确定当帧与原始视频尺寸不匹配时如何调整视频大小。 "none"(默认) - 不匹配大小 contain、cover、stretch
fullscreen={false}
fullscreenAutorotate={true}
fullscreenOrientation={'landscape'}
onLoad={this.onLoad} //加载媒体并准备播放时调用的回调函数。
onLoadStart={this.onLoadStart} //媒体开始加载时调用的回调函数。
onProgress={this.onProgress} //视频播放过程中每个间隔进度单位(通常不足一秒,你可以打印日志测试下)调用的回调,其中包含有关媒体当前正在播放的位置的信息。
onSeek={this.onSeek}
onBuffer={this.onBuffer} // 远程视频缓冲时的回调
onError={this.videoError} // 播放失败后的回调
onEnd={this.onEnd} // 播放完成后的回调
// onTimedMetadata={this.onTimedMetadata} // 当定时元数据可用时调用的回调函数.
onAudioBecomingNoisy={this.onAudioBecomingNoisy}
onAudioFocusChanged={this.onAudioFocusChanged}
repeat={true} //视频放完后是否重播
/>
{this.renderBottom(item,index)}
{this.renderRight(item,index)}
</View>
);
}
renderVideoList(){
let height = Util.size.height
let video_list = this.state.video_list
let arr = []
video_list.map((item,id)=>{
arr.push(height*(id)) //各个视图所能够滚动的高度
})
return(
<View style={{flex:1}}>
<FlatList
style={{flex: 1}}
pagingEnabled
showsVerticalScrollIndicator={false}
data={this.state.video_list}
numColumns={1}
renderItem={this.renderItem}
keyExtractor={item => String(item.id)}
onEndReached={this.onEndReached.bind(this)}
// ListFooterComponent={this.renderFooter.bind(this)}
onScroll={Animated.event(
[{ nativeEvent: {contentOffset: { y: 0 }}}], //初始化滚动的距离
{ listener: (event) => {
let scrollY = event.nativeEvent.contentOffset.y
console.log('获取滚动的距离',scrollY)
arr.map((item,id)=>{
if(item === scrollY){
console.log('id===',id,)
video_list[id].paused = false
this.setState({
curVideoIndex:id
})
}else{
video_list[id].paused = true
video_list[id].currentTime = 0.0
}
})
this.setState({
video_list
})
}
}
)}
/>
</View>
)
}
renderRight(item1){
let arr = [
{img:require('../images/live/love.png'),value:284},
{img:require('../images/live/msg_icon.png'),value:14},
{img:require('../images/live/zhuanfa.png'),value:23.3},
]
return(
<View style={{position:'absolute',right:10,bottom:'17%',}}>
<View style={{alignItems:'center'}}>
<Image source={require('../images/logo.png')} style={{width:50,height:50,borderRadius:999}}/>
<Image source={require('../images/live/add_focus_icon.png')} style={{width:24,height:24,borderRadius:999,top:-10}}/>
</View>
{
arr.map((item,id)=>{
return(
<TouchableOpacity
onPress={()=>this._onPress(id)}
key={id}
style={{alignItems:'center',marginVertical:10}}>
<Image source={item.img} style={{width:40,height:40}}/>
<Text style={{color:'#fff',fontSize:12}}>{item.value}w</Text>
</TouchableOpacity>
)
})
}
</View>
)
}
renderBottom(item){
const flexCompleted = this.getCurrentTimePercentage() * 100;
const flexRemaining = (1 - this.getCurrentTimePercentage()) * 100;
return(
<View style={{position:'absolute',bottom:0,width:'100%',}}>
<Text style={{fontSize:40,color:'#fff'}} onPress={()=>this.onPaused()}>暂停/播放</Text>
<Text style={{fontSize:40,color:'#fff'}} onPress={()=>this.onMoveSeek()}>定位播放位置</Text>
<View style={{paddingHorizontal:15}}>
<Text style={{fontSize:16,color:'#fff',fontWeight:'bold'}}>用户名称</Text>
<Text style={{fontSize:13,color:'rgba(255,255,255,0.6)',paddingVertical:10}}>{item.title}</Text>
</View>
{/*进度条*/}
<View style={Styles.progress}>
<View style={[Styles.innerProgressCompleted, { flex: flexCompleted }]} />
<View style={[Styles.innerProgressRemaining, { flex: flexRemaining }]} />
</View>
<View style={{paddingHorizontal:15,paddingVertical:10}}>
<View style={{
height:40,justifyContent:'center',
borderWidth: 1,
borderColor: 'rgba(255,255,255,0.2)',
borderRadius:999,
flex:1,
// backgroundColor:'red'
}}>
<TextInput
placeholder="说点什么吧~"
placeholderTextColor='rgba(255,255,255,0.6)'
multiline={false}
maxLength={120}
style={{fontSize:12,height:40,marginLeft:10,color:'#fff'}}
onChangeText={(text)=>this.setState({title:text})}
underlineColorAndroid={'transparent'}
/>
</View>
</View>
</View>
)
}
renderBack(){
return(
<TouchableOpacity
onPress={()=>this.props.navigation.pop()}
style={{position:'absolute',left:15,top:40,zIndex:1}}>
<Image source={require('../images/live/back_icon.png')} style={{height:25,width:25}}/>
</TouchableOpacity>
)
}
render() {
return (
<View style={{flex:1,backgroundColor:'rgba(0,0,0,0.5)'}}>
{this.renderBack()}
{this.renderVideoList()}
</View>
);
}
}
export default TVideoDetail;
const Styles = StyleSheet.create({
fullScreen: {
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
},
progress: {
flex: 1,
alignItems:'center',
flexDirection: 'row',
borderRadius: 3,
overflow: 'hidden',
},
innerProgressCompleted: {
height: 2,
backgroundColor: 'rgba(255, 198, 0, 1)',
},
innerProgressRemaining: {
height: 2,
backgroundColor: '#fff',
},
})
官网Video组件
'use strict';
import React, {
Component
} from 'react';
import {
AlertIOS,
AppRegistry,
Platform,
StyleSheet,
Text,
TouchableOpacity,
View,
} from 'react-native';
import Video,{FilterType} from 'react-native-video';
const filterTypes = [
FilterType.NONE,
FilterType.INVERT,
FilterType.MONOCHROME,
FilterType.POSTERIZE,
FilterType.FALSE,
FilterType.MAXIMUMCOMPONENT,
FilterType.MINIMUMCOMPONENT,
FilterType.CHROME,
FilterType.FADE,
FilterType.INSTANT,
FilterType.MONO,
FilterType.NOIR,
FilterType.PROCESS,
FilterType.TONAL,
FilterType.TRANSFER,
FilterType.SEPIA
];
class VideoPlayer extends Component {
constructor(props) {
super(props);
this.onLoad = this.onLoad.bind(this);
this.onProgress = this.onProgress.bind(this);
this.onBuffer = this.onBuffer.bind(this);
}
state = {
rate: 1,
volume: 1,
muted: false,
resizeMode: 'contain',
duration: 0.0,
currentTime: 0.0,
controls: false,
paused: true,
skin: 'custom',
ignoreSilentSwitch: null,
mixWithOthers: null,
isBuffering: false,
filter: FilterType.NONE,
filterEnabled: true
};
onLoad(data) {
console.log('On load fired!');
this.setState({duration: data.duration});
}
onProgress(data) {
this.setState({currentTime: data.currentTime});
}
onBuffer({ isBuffering }: { isBuffering: boolean }) {
this.setState({ isBuffering });
}
getCurrentTimePercentage() {
if (this.state.currentTime > 0) {
return parseFloat(this.state.currentTime) / parseFloat(this.state.duration);
} else {
return 0;
}
}
setFilter(step) {
let index = filterTypes.indexOf(this.state.filter) + step;
if (index === filterTypes.length) {
index = 0;
} else if (index === -1) {
index = filterTypes.length - 1;
}
this.setState({
filter: filterTypes[index]
})
}
renderSkinControl(skin) {
const isSelected = this.state.skin == skin;
const selectControls = skin == 'native' || skin == 'embed';
return (
<TouchableOpacity onPress={() => { this.setState({
controls: selectControls,
skin: skin
}) }}>
<Text style={[styles.controlOption, {fontWeight: isSelected ? "bold" : "normal"}]}>
{skin}
</Text>
</TouchableOpacity>
);
}
renderRateControl(rate) {
const isSelected = (this.state.rate == rate);
return (
<TouchableOpacity onPress={() => { this.setState({rate: rate}) }}>
<Text style={[styles.controlOption, {fontWeight: isSelected ? "bold" : "normal"}]}>
{rate}x
</Text>
</TouchableOpacity>
)
}
renderResizeModeControl(resizeMode) {
const isSelected = (this.state.resizeMode == resizeMode);
return (
<TouchableOpacity onPress={() => { this.setState({resizeMode: resizeMode}) }}>
<Text style={[styles.controlOption, {fontWeight: isSelected ? "bold" : "normal"}]}>
{resizeMode}
</Text>
</TouchableOpacity>
)
}
renderVolumeControl(volume) {
const isSelected = (this.state.volume == volume);
return (
<TouchableOpacity onPress={() => { this.setState({volume: volume}) }}>
<Text style={[styles.controlOption, {fontWeight: isSelected ? "bold" : "normal"}]}>
{volume * 100}%
</Text>
</TouchableOpacity>
)
}
renderIgnoreSilentSwitchControl(ignoreSilentSwitch) {
const isSelected = (this.state.ignoreSilentSwitch == ignoreSilentSwitch);
return (
<TouchableOpacity onPress={() => { this.setState({ignoreSilentSwitch: ignoreSilentSwitch}) }}>
<Text style={[styles.controlOption, {fontWeight: isSelected ? "bold" : "normal"}]}>
{ignoreSilentSwitch}
</Text>
</TouchableOpacity>
)
}
renderMixWithOthersControl(mixWithOthers) {
const isSelected = (this.state.mixWithOthers == mixWithOthers);
return (
<TouchableOpacity onPress={() => { this.setState({mixWithOthers: mixWithOthers}) }}>
<Text style={[styles.controlOption, {fontWeight: isSelected ? "bold" : "normal"}]}>
{mixWithOthers}
</Text>
</TouchableOpacity>
)
}
renderCustomSkin() {
const flexCompleted = this.getCurrentTimePercentage() * 100;
const flexRemaining = (1 - this.getCurrentTimePercentage()) * 100;
return (
<View style={styles.container}>
<TouchableOpacity style={styles.fullScreen} onPress={() => {this.setState({paused: !this.state.paused})}}>
<Video
source={{uri:'http://vfx.mtime.cn/Video/2019/02/04/mp4/190204084208765161.mp4'}}
style={styles.fullScreen}
rate={this.state.rate}
paused={this.state.paused}
volume={this.state.volume}
muted={this.state.muted}
ignoreSilentSwitch={this.state.ignoreSilentSwitch}
mixWithOthers={this.state.mixWithOthers}
resizeMode={this.state.resizeMode}
onLoad={this.onLoad}
onBuffer={this.onBuffer}
onProgress={this.onProgress}
onEnd={() => { AlertIOS.alert('Done!') }}
repeat={true}
filter={this.state.filter}
filterEnabled={this.state.filterEnabled}
/>
</TouchableOpacity>
<View style={styles.controls}>
<View style={styles.generalControls}>
<View style={styles.skinControl}>
{this.renderSkinControl('custom')}
{this.renderSkinControl('native')}
{this.renderSkinControl('embed')}
</View>
{
(this.state.filterEnabled) ?
<View style={styles.skinControl}>
<TouchableOpacity onPress={() => {
this.setFilter(-1)
}}>
<Text style={styles.controlOption}>Previous Filter</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => {
this.setFilter(1)
}}>
<Text style={styles.controlOption}>Next Filter</Text>
</TouchableOpacity>
</View> : null
}
</View>
<View style={styles.generalControls}>
<View style={styles.rateControl}>
{this.renderRateControl(0.5)}
{this.renderRateControl(1.0)}
{this.renderRateControl(2.0)}
</View>
<View style={styles.volumeControl}>
{this.renderVolumeControl(0.5)}
{this.renderVolumeControl(1)}
{this.renderVolumeControl(1.5)}
</View>
<View style={styles.resizeModeControl}>
{this.renderResizeModeControl('cover')}
{this.renderResizeModeControl('contain')}
{this.renderResizeModeControl('stretch')}
</View>
</View>
<View style={styles.generalControls}>
{
(Platform.OS === 'ios') ?
<>
<View style={styles.ignoreSilentSwitchControl}>
{this.renderIgnoreSilentSwitchControl('ignore')}
{this.renderIgnoreSilentSwitchControl('obey')}
</View>
<View style={styles.mixWithOthersControl}>
{this.renderMixWithOthersControl('mix')}
{this.renderMixWithOthersControl('duck')}
</View>
</> : null
}
</View>
<View style={styles.trackingControls}>
<View style={styles.progress}>
<View style={[styles.innerProgressCompleted, {flex: flexCompleted}]} />
<View style={[styles.innerProgressRemaining, {flex: flexRemaining}]} />
</View>
</View>
</View>
</View>
);
}
renderNativeSkin() {
const videoStyle = this.state.skin == 'embed' ? styles.nativeVideoControls : styles.fullScreen;
return (
<View style={styles.container}>
<View style={styles.fullScreen}>
<Video
source={{uri:'http://vfx.mtime.cn/Video/2019/02/04/mp4/190204084208765161.mp4'}}
style={videoStyle}
rate={this.state.rate}
paused={this.state.paused}
volume={this.state.volume}
muted={this.state.muted}
ignoreSilentSwitch={this.state.ignoreSilentSwitch}
mixWithOthers={this.state.mixWithOthers}
resizeMode={this.state.resizeMode}
onLoad={this.onLoad}
onBuffer={this.onBuffer}
onProgress={this.onProgress}
onEnd={() => { AlertIOS.alert('Done!') }}
repeat={true}
controls={this.state.controls}
filter={this.state.filter}
filterEnabled={this.state.filterEnabled}
/>
</View>
<View style={styles.controls}>
<View style={styles.generalControls}>
<View style={styles.skinControl}>
{this.renderSkinControl('custom')}
{this.renderSkinControl('native')}
{this.renderSkinControl('embed')}
</View>
{
(this.state.filterEnabled) ?
<View style={styles.skinControl}>
<TouchableOpacity onPress={() => {
this.setFilter(-1)
}}>
<Text style={styles.controlOption}>Previous Filter</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => {
this.setFilter(1)
}}>
<Text style={styles.controlOption}>Next Filter</Text>
</TouchableOpacity>
</View> : null
}
</View>
<View style={styles.generalControls}>
<View style={styles.rateControl}>
{this.renderRateControl(0.5)}
{this.renderRateControl(1.0)}
{this.renderRateControl(2.0)}
</View>
<View style={styles.volumeControl}>
{this.renderVolumeControl(0.5)}
{this.renderVolumeControl(1)}
{this.renderVolumeControl(1.5)}
</View>
<View style={styles.resizeModeControl}>
{this.renderResizeModeControl('cover')}
{this.renderResizeModeControl('contain')}
{this.renderResizeModeControl('stretch')}
</View>
</View>
<View style={styles.generalControls}>
{
(Platform.OS === 'ios') ?
<>
<View style={styles.ignoreSilentSwitchControl}>
{this.renderIgnoreSilentSwitchControl('ignore')}
{this.renderIgnoreSilentSwitchControl('obey')}
</View>
<View style={styles.mixWithOthersControl}>
{this.renderMixWithOthersControl('mix')}
{this.renderMixWithOthersControl('duck')}
</View>
</> : null
}
</View>
</View>
</View>
);
}
render() {
return this.state.controls ? this.renderNativeSkin() : this.renderCustomSkin();
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: 'black',
},
fullScreen: {
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
right: 0,
},
controls: {
backgroundColor: "transparent",
borderRadius: 5,
position: 'absolute',
bottom: 44,
left: 4,
right: 4,
},
progress: {
flex: 1,
flexDirection: 'row',
borderRadius: 3,
overflow: 'hidden',
},
innerProgressCompleted: {
height: 20,
backgroundColor: '#cccccc',
},
innerProgressRemaining: {
height: 20,
backgroundColor: '#2C2C2C',
},
generalControls: {
flex: 1,
flexDirection: 'row',
overflow: 'hidden',
paddingBottom: 10,
},
skinControl: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
},
rateControl: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
},
volumeControl: {
flex: 1,
flexDirection: 'row',
justifyContent: 'center',
},
resizeModeControl: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center'
},
ignoreSilentSwitchControl: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center'
},
mixWithOthersControl: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center'
},
controlOption: {
alignSelf: 'center',
fontSize: 11,
color: "white",
paddingLeft: 2,
paddingRight: 2,
lineHeight: 12,
},
nativeVideoControls: {
top: 184,
height: 300
}
});
export default VideoPlayer