|
@@ -7,6 +7,7 @@ import {
|
|
|
Button,
|
|
|
Image,
|
|
|
TouchableOpacity,
|
|
|
+ PanResponder,
|
|
|
StyleSheet
|
|
|
} from "react-native";
|
|
|
import { createStackNavigator, createAppContainer } from "react-navigation";
|
|
@@ -21,7 +22,20 @@ const instructions = Platform.select({
|
|
|
|
|
|
type Props = {};
|
|
|
export default class CusVideo extends React.Component {
|
|
|
+ constructor(props) {
|
|
|
+ super(props);
|
|
|
+ this.pressStatus = false;
|
|
|
+ this.progress = 0;
|
|
|
+ }
|
|
|
+ config = {
|
|
|
+ changeX: 0,
|
|
|
+ changeY: 0,
|
|
|
+ xDiff: 0,
|
|
|
+ yDiff: 0
|
|
|
+ };
|
|
|
+
|
|
|
state = {
|
|
|
+ player_status_icon: require("../images/video/start.png"),
|
|
|
rate: 1,
|
|
|
volume: 1,
|
|
|
muted: false,
|
|
@@ -30,15 +44,20 @@ export default class CusVideo extends React.Component {
|
|
|
currentTime: 0.0,
|
|
|
paused: false,
|
|
|
wheel: false,
|
|
|
- player_status_icon: require("../images/video/start.png"),
|
|
|
isFull: false,
|
|
|
- needback: this.props.needback
|
|
|
+ needback: this.props.needback,
|
|
|
+ show_controller: true,
|
|
|
+ show_loading: true
|
|
|
};
|
|
|
|
|
|
render() {
|
|
|
+ if (!this.props.show) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
return (
|
|
|
- <View style={this.props.style}>
|
|
|
+ <View style={[this.props.style, { overflow: "hidden" }]}>
|
|
|
<Video
|
|
|
+ {...this.videotouch.panHandlers}
|
|
|
style={{ flex: 1 }}
|
|
|
source={{
|
|
|
uri: this.props.uri
|
|
@@ -47,9 +66,9 @@ export default class CusVideo extends React.Component {
|
|
|
this.player = ref;
|
|
|
}}
|
|
|
|
|
|
- resizeMode={this.state.resizeMode}
|
|
|
+ resizeMode={[this.state.resizeMode]}
|
|
|
|
|
|
- onBuffer={this.onBuffer}
|
|
|
+ onBuffer={this.onBuffer.bind(this)}
|
|
|
rate={this.state.rate}
|
|
|
paused={this.state.paused}
|
|
|
volume={this.state.volume}
|
|
@@ -68,132 +87,108 @@ export default class CusVideo extends React.Component {
|
|
|
/>
|
|
|
<View
|
|
|
style={{
|
|
|
- flexDirection: "row",
|
|
|
position: "absolute",
|
|
|
width: "100%",
|
|
|
- height: 50,
|
|
|
+ height: "100%",
|
|
|
alignItems: "center",
|
|
|
justifyContent: "center"
|
|
|
}}
|
|
|
>
|
|
|
- <View
|
|
|
- style={{
|
|
|
- flex: 1,
|
|
|
- alignItems: "center"
|
|
|
- }}
|
|
|
- >
|
|
|
- <VideoBack
|
|
|
- needback={this.state.needback}
|
|
|
- videoback={this.videoBackClick.bind(this)}
|
|
|
- />
|
|
|
- </View>
|
|
|
- <View style={{ flex: 2 }} />
|
|
|
- <View
|
|
|
- style={{
|
|
|
- flex: 9,
|
|
|
- overflow: "hidden"
|
|
|
- }}
|
|
|
- />
|
|
|
- <View style={{ flex: 2 }} />
|
|
|
- <View
|
|
|
- style={{
|
|
|
- flex: 1,
|
|
|
- alignItems: "center"
|
|
|
- }}
|
|
|
- />
|
|
|
- </View>
|
|
|
- <View style={[styles.player_controller]}>
|
|
|
- <View
|
|
|
- style={{
|
|
|
- flex: 1,
|
|
|
- alignItems: "center"
|
|
|
- }}
|
|
|
- >
|
|
|
- {}
|
|
|
- <TouchableOpacity
|
|
|
-
|
|
|
- style={{
|
|
|
- justifyContent: "center",
|
|
|
- width: "100%",
|
|
|
- height: "100%"
|
|
|
- }}
|
|
|
- onPress={() => this.play()}
|
|
|
- >
|
|
|
- <Image
|
|
|
- style={[styles.player_pause_icon]}
|
|
|
- source={this.state.player_status_icon}
|
|
|
- />
|
|
|
- </TouchableOpacity>
|
|
|
- </View>
|
|
|
- <View style={{ flex: 2 }}>
|
|
|
- {}
|
|
|
- <Text style={[styles.player_time]}>
|
|
|
- {formatTime(this.state.currentTime)}
|
|
|
- </Text>
|
|
|
- </View>
|
|
|
- <View
|
|
|
- style={{
|
|
|
- flex: 9,
|
|
|
- overflow: "hidden"
|
|
|
- }}
|
|
|
- >
|
|
|
- {}
|
|
|
- <SeekBar
|
|
|
- style={{ flex: 1 }}
|
|
|
- ref={view => (this.seekbar = view)}
|
|
|
-
|
|
|
- touchUpCallBack={this.touch_up_callback.bind(this)}
|
|
|
- />
|
|
|
- </View>
|
|
|
- <View style={{ flex: 2 }}>
|
|
|
- {}
|
|
|
- <Text style={[styles.player_time]}>
|
|
|
- {formatTime(this.state.duration)}
|
|
|
- </Text>
|
|
|
- </View>
|
|
|
- <View
|
|
|
- style={{
|
|
|
- flex: 1,
|
|
|
- alignItems: "center"
|
|
|
- }}
|
|
|
- >
|
|
|
- <TouchableOpacity
|
|
|
- style={{
|
|
|
- justifyContent: "center",
|
|
|
- width: "100%",
|
|
|
- height: "100%"
|
|
|
- }}
|
|
|
- onPress={() => this.presentFullscreenPlayer()}
|
|
|
- >
|
|
|
- {}
|
|
|
- <Image
|
|
|
- style={[styles.fullscreen_icon]}
|
|
|
- source={require("../images/video/fullscreen.png")}
|
|
|
- />
|
|
|
- </TouchableOpacity>
|
|
|
- </View>
|
|
|
+ <Loading show={this.state.show_loading} />
|
|
|
</View>
|
|
|
+ <TopController
|
|
|
+ ref={view => (this.topcontroller = view)}
|
|
|
+ needback={this.state.needback}
|
|
|
+ videoback={this.videoBackClick.bind(this)}
|
|
|
+ />
|
|
|
+ <BottomController
|
|
|
+ ref={view => (this.bottomcontroller = view)}
|
|
|
+ show={this.state.show_controller}
|
|
|
+ touch_up_callback={this.touch_up_callback.bind(this)}
|
|
|
+ full_click={this.presentFullscreenPlayer.bind(this)}
|
|
|
+ play_click={this.play.bind(this)}
|
|
|
+ duration={this.state.duration}
|
|
|
+ currentTime={this.state.currentTime}
|
|
|
+ player_status_icon={this.state.player_status_icon}
|
|
|
+ />
|
|
|
</View>
|
|
|
);
|
|
|
}
|
|
|
|
|
|
+ componentWillMount() {
|
|
|
+ this.videotouch = PanResponder.create({
|
|
|
+ onStartShouldSetPanResponder: (evt, gestureState) => true,
|
|
|
+ onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
|
|
|
+ onMoveShouldSetPanResponder: (evt, gestureState) => true,
|
|
|
+ onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
|
|
|
+
|
|
|
+ onPanResponderGrant: (evt, gestureState) => {
|
|
|
+ this.pressStatus = true;
|
|
|
+ this.config.changeY = evt.nativeEvent.pageY;
|
|
|
+ this.config.changeX = evt.nativeEvent.pageX;
|
|
|
+ if (this.state.show_controller) {
|
|
|
+ this.hideController();
|
|
|
+ } else {
|
|
|
+ this.showController();
|
|
|
+ }
|
|
|
+ console.log("onPanResponderGrant");
|
|
|
+ },
|
|
|
+ onPanResponderStart: (evt, gestureState) => {
|
|
|
+ this.pressStatus = true;
|
|
|
+ console.log("onPanResponderStart");
|
|
|
+ },
|
|
|
+ onPanResponderMove: (evt, gestureState) => {
|
|
|
+ this.config.yDiff = evt.nativeEvent.pageY - this.config.changeY;
|
|
|
+ this.config.xDiff = evt.nativeEvent.pageX - this.config.changeX;
|
|
|
+ this.config.changeY = evt.nativeEvent.pageY;
|
|
|
+ this.config.changeX = evt.nativeEvent.pageX;
|
|
|
+ },
|
|
|
+ onPanResponderEnd: (evt, gestureState) => {
|
|
|
+ this.pressStatus = true;
|
|
|
+ console.log("onPanResponderEnd");
|
|
|
+ },
|
|
|
+ onPanResponderTerminationRequest: (evt, gestureState) => true,
|
|
|
+ onPanResponderRelease: (evt, gestureState) => {
|
|
|
+ if (this.pressStatus) {
|
|
|
+ this.props.onPress && this.props.onPress();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onPanResponderTerminate: (evt, gestureState) => {
|
|
|
+
|
|
|
+ },
|
|
|
+ onShouldBlockNativeResponder: (evt, gestureState) => {
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
loadStart() {
|
|
|
|
|
|
}
|
|
|
+
|
|
|
onBuffer({ isBuffering }: { isBuffering: boolean }) {
|
|
|
|
|
|
+ this.setState({
|
|
|
+ show_loading: isBuffering
|
|
|
+ });
|
|
|
console.log("isBuffering:" + isBuffering);
|
|
|
}
|
|
|
onLoad = data => {
|
|
|
|
|
|
this.setState({ duration: data.duration });
|
|
|
- this.seekbar.setMax(data.duration);
|
|
|
+ this.bottomcontroller.setMax(data.duration);
|
|
|
};
|
|
|
onProgress = data => {
|
|
|
this.setState({
|
|
|
currentTime: data.currentTime
|
|
|
});
|
|
|
- this.seekbar.setProgress(this.state.currentTime);
|
|
|
+ if (this.state.show_controller) {
|
|
|
+ this.bottomcontroller.setProgress(this.state.currentTime);
|
|
|
+ this.bottomcontroller.setMax(this.state.duration);
|
|
|
+ }
|
|
|
};
|
|
|
|
|
|
onError() {
|
|
@@ -203,6 +198,7 @@ export default class CusVideo extends React.Component {
|
|
|
alert("播放结束");
|
|
|
}
|
|
|
play() {
|
|
|
+
|
|
|
if (this.state.paused) {
|
|
|
this.start();
|
|
|
} else {
|
|
@@ -223,10 +219,7 @@ export default class CusVideo extends React.Component {
|
|
|
});
|
|
|
this.player_icon_index = 0;
|
|
|
}
|
|
|
- showToast(params) {
|
|
|
-
|
|
|
- ToastExample.show(params, ToastExample.SHORT);
|
|
|
- }
|
|
|
+
|
|
|
seekTo(progress) {
|
|
|
this.player.seek(progress);
|
|
|
}
|
|
@@ -244,7 +237,7 @@ export default class CusVideo extends React.Component {
|
|
|
}
|
|
|
|
|
|
this.props.videofullScreenPlayer();
|
|
|
- this.seekbar.setProgress(this.state.currentTime);
|
|
|
+ this.bottomcontroller.setProgress(this.state.currentTime);
|
|
|
}
|
|
|
touch_up_callback(progress) {
|
|
|
|
|
@@ -271,8 +264,243 @@ export default class CusVideo extends React.Component {
|
|
|
this.props.videoback();
|
|
|
}
|
|
|
}
|
|
|
+ showController() {
|
|
|
+ this.setState({
|
|
|
+ show_controller: true
|
|
|
+
|
|
|
+ });
|
|
|
+ this.bottomcontroller.setBottom(0);
|
|
|
+ this.topcontroller.setTop(0);
|
|
|
+ }
|
|
|
+ hideController() {
|
|
|
+ this.setState({
|
|
|
+ show_controller: false
|
|
|
+
|
|
|
+ });
|
|
|
+ this.bottomcontroller.setBottom(-50);
|
|
|
+ this.topcontroller.setTop(-50);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+ * 将秒转换为 分:秒
|
|
|
+ * s int 秒数
|
|
|
+ */
|
|
|
+function formatTime(s) {
|
|
|
+
|
|
|
+
|
|
|
+ var h;
|
|
|
+ h = Math.floor(s / 60);
|
|
|
+
|
|
|
+
|
|
|
+ s = Math.round(s % 60);
|
|
|
+
|
|
|
+ h += "";
|
|
|
+ s += "";
|
|
|
+
|
|
|
+ h = h.length == 1 ? "0" + h : h;
|
|
|
+ s = s.length == 1 ? "0" + s : s;
|
|
|
+ return h + ":" + s;
|
|
|
+}
|
|
|
+class TopController extends Component {
|
|
|
+ state = {
|
|
|
+ controller_top: 0
|
|
|
+ };
|
|
|
+ render() {
|
|
|
+ if (this.props.needback == false) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return (
|
|
|
+ <View
|
|
|
+ style={[styles.player_controller, { top: this.state.controller_top }]}
|
|
|
+ >
|
|
|
+ <View
|
|
|
+ style={{
|
|
|
+ flex: 1,
|
|
|
+ alignItems: "center"
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <TouchableOpacity
|
|
|
+
|
|
|
+ style={{
|
|
|
+ justifyContent: "center",
|
|
|
+ width: "100%",
|
|
|
+ height: "100%"
|
|
|
+ }}
|
|
|
+ onPress={() => this.props.videoback()}
|
|
|
+ >
|
|
|
+ <Image
|
|
|
+ style={[styles.player_pause_icon]}
|
|
|
+ source={require("../images/video/back.png")}
|
|
|
+ />
|
|
|
+ </TouchableOpacity>
|
|
|
+ </View>
|
|
|
+ <View style={{ flex: 2 }} />
|
|
|
+ <View
|
|
|
+ style={{
|
|
|
+ flex: 9,
|
|
|
+ overflow: "hidden"
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ <View style={{ flex: 2 }} />
|
|
|
+ <View
|
|
|
+ style={{
|
|
|
+ flex: 1,
|
|
|
+ alignItems: "center"
|
|
|
+ }}
|
|
|
+ />
|
|
|
+ </View>
|
|
|
+ );
|
|
|
+ }
|
|
|
+
|
|
|
+ setTop(top) {
|
|
|
+ this.setState({
|
|
|
+ controller_top: top
|
|
|
+ });
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+class Loading extends Component {
|
|
|
+ state = {
|
|
|
+ image_arr: [
|
|
|
+ require("../images/video/loading1.png"),
|
|
|
+ require("../images/video/loading2.png"),
|
|
|
+ require("../images/video/loading3.png"),
|
|
|
+ require("../images/video/loading3.png"),
|
|
|
+ require("../images/video/loading4.png"),
|
|
|
+ require("../images/video/loading5.png"),
|
|
|
+ require("../images/video/loading6.png"),
|
|
|
+ require("../images/video/loading7.png"),
|
|
|
+ require("../images/video/loading8.png"),
|
|
|
+ require("../images/video/loading9.png"),
|
|
|
+ require("../images/video/loading10.png"),
|
|
|
+ require("../images/video/loading11.png"),
|
|
|
+ require("../images/video/loading12.png"),
|
|
|
+ require("../images/video/loading13.png"),
|
|
|
+ require("../images/video/loading14.png"),
|
|
|
+ require("../images/video/loading15.png"),
|
|
|
+ require("../images/video/loading16.png"),
|
|
|
+ require("../images/video/loading17.png"),
|
|
|
+ require("../images/video/loading18.png"),
|
|
|
+ require("../images/video/loading19.png"),
|
|
|
+ require("../images/video/loading20.png")
|
|
|
+ ],
|
|
|
+ loading_index: 0
|
|
|
+ };
|
|
|
+ render() {
|
|
|
+ if (this.props.show) {
|
|
|
+ return (
|
|
|
+ <Image
|
|
|
+ source={this.state.image_arr[this.state.loading_index]}
|
|
|
+ style={{ width: "20%", height: "10%", backgroundColor: "blue" }}
|
|
|
+ />
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
+class BottomController extends Component {
|
|
|
+ state = {
|
|
|
+ controller_bottom: 0
|
|
|
+ };
|
|
|
+
|
|
|
+ render() {
|
|
|
+ return (
|
|
|
+ <View
|
|
|
+ style={[
|
|
|
+ styles.player_controller,
|
|
|
+ { bottom: this.state.controller_bottom }
|
|
|
+ ]}
|
|
|
+ >
|
|
|
+ <View
|
|
|
+ style={{
|
|
|
+ flex: 1,
|
|
|
+ alignItems: "center"
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {}
|
|
|
+ <TouchableOpacity
|
|
|
+
|
|
|
+ style={{
|
|
|
+ justifyContent: "center",
|
|
|
+ width: "100%",
|
|
|
+ height: "100%"
|
|
|
+ }}
|
|
|
+ onPress={() => this.props.play_click()}
|
|
|
+ >
|
|
|
+ <Image
|
|
|
+ style={[styles.player_pause_icon]}
|
|
|
+ source={this.props.player_status_icon}
|
|
|
+ />
|
|
|
+ </TouchableOpacity>
|
|
|
+ </View>
|
|
|
+ <View style={{ flex: 2 }}>
|
|
|
+ {}
|
|
|
+ <Text style={[styles.player_time]}>
|
|
|
+ {formatTime(this.props.currentTime)}
|
|
|
+ </Text>
|
|
|
+ </View>
|
|
|
+ <View
|
|
|
+ style={{
|
|
|
+ flex: 9,
|
|
|
+ overflow: "hidden"
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ {}
|
|
|
+ <SeekBar
|
|
|
+ style={{ flex: 1 }}
|
|
|
+ ref={view => (this.seekbar = view)}
|
|
|
+
|
|
|
+ touchUpCallBack={this.props.touch_up_callback}
|
|
|
+ />
|
|
|
+ </View>
|
|
|
+ <View style={{ flex: 2 }}>
|
|
|
+ {}
|
|
|
+ <Text style={[styles.player_time]}>
|
|
|
+ {formatTime(this.props.duration)}
|
|
|
+ </Text>
|
|
|
+ </View>
|
|
|
+ <View
|
|
|
+ style={{
|
|
|
+ flex: 1,
|
|
|
+ alignItems: "center"
|
|
|
+ }}
|
|
|
+ >
|
|
|
+ <TouchableOpacity
|
|
|
+ style={{
|
|
|
+ justifyContent: "center",
|
|
|
+ width: "100%",
|
|
|
+ height: "100%"
|
|
|
+ }}
|
|
|
+ onPress={() => this.props.full_click()}
|
|
|
+ >
|
|
|
+ {}
|
|
|
+ <Image
|
|
|
+ style={[styles.fullscreen_icon]}
|
|
|
+ source={require("../images/video/fullscreen.png")}
|
|
|
+ />
|
|
|
+ </TouchableOpacity>
|
|
|
+ </View>
|
|
|
+ </View>
|
|
|
+ );
|
|
|
+ }
|
|
|
+ setMax(duration) {
|
|
|
+ this.seekbar.setMax(duration);
|
|
|
+ }
|
|
|
+ getMax() {
|
|
|
+ return this.seekbar.getMax();
|
|
|
+ }
|
|
|
+ setBottom(bottom) {
|
|
|
+ this.setState({
|
|
|
+ controller_bottom: bottom
|
|
|
+ });
|
|
|
+ }
|
|
|
+ setProgress(currentTime) {
|
|
|
+ this.seekbar.setProgress(currentTime);
|
|
|
+ }
|
|
|
+}
|
|
|
const styles = StyleSheet.create({
|
|
|
player_controller: {
|
|
|
flexDirection: "row",
|
|
@@ -280,8 +508,7 @@ const styles = StyleSheet.create({
|
|
|
width: "100%",
|
|
|
height: 50,
|
|
|
alignItems: "center",
|
|
|
- justifyContent: "center",
|
|
|
- bottom: 0
|
|
|
+ justifyContent: "center"
|
|
|
},
|
|
|
player_pause_icon: {
|
|
|
width: "80%",
|
|
@@ -309,51 +536,6 @@ const styles = StyleSheet.create({
|
|
|
});
|
|
|
|
|
|
|
|
|
- * 将秒转换为 分:秒
|
|
|
- * s int 秒数
|
|
|
- */
|
|
|
-function formatTime(s) {
|
|
|
-
|
|
|
-
|
|
|
- var h;
|
|
|
- h = Math.floor(s / 60);
|
|
|
-
|
|
|
-
|
|
|
- s = Math.round(s % 60);
|
|
|
-
|
|
|
- h += "";
|
|
|
- s += "";
|
|
|
-
|
|
|
- h = h.length == 1 ? "0" + h : h;
|
|
|
- s = s.length == 1 ? "0" + s : s;
|
|
|
- return h + ":" + s;
|
|
|
-}
|
|
|
-class VideoBack extends Component {
|
|
|
- render() {
|
|
|
- if (this.props.needback) {
|
|
|
- return (
|
|
|
- <TouchableOpacity
|
|
|
-
|
|
|
- style={{
|
|
|
- justifyContent: "center",
|
|
|
- width: "100%",
|
|
|
- height: "100%"
|
|
|
- }}
|
|
|
- onPress={() => this.props.videoback()}
|
|
|
- >
|
|
|
- <Image
|
|
|
- style={[styles.player_pause_icon]}
|
|
|
- source={require("../images/video/back.png")}
|
|
|
- />
|
|
|
- </TouchableOpacity>
|
|
|
- );
|
|
|
- } else {
|
|
|
- return null;
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
使用方法
|
|
|
<CusVideo
|
|
|
uri={this.state.video_uri}
|