Browse Source

1.修改播放器
2.修改课程表界面
3.修改进度条组件

zhangmengjie 5 years ago
parent
commit
faf7f8bcca
3 changed files with 406 additions and 192 deletions
  1. 339 157
      pages/components/CusVideo.js
  2. 63 34
      pages/components/SchedulePage.js
  3. 4 1
      pages/components/SeekBar.js

+ 339 - 157
pages/components/CusVideo.js

@@ -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;
           }}
           // poster={this.props.poster}
-          resizeMode={this.state.resizeMode}
+          resizeMode={[this.state.resizeMode]}
           // posterResizeMode={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) => {
+        // 返回一个布尔值,决定当前组件是否应该阻止原生组件成为JS响应者
+        // 默认返回true。目前暂时只支持android。
+        //基于业务交互场景,如果这里使用js事件处理,会导致容器不能左右滑动。所以设置成false.
+        return false;
+      }
+    });
+  }
+
   loadStart() {
     // alert("loadStart");
   }
+
   onBuffer({ isBuffering }: { isBuffering: boolean }) {
     //true为正在加载,false为没有加载,此处给loading提示
+    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() {
+    //controller的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.message(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) {
     //抬起之后,获取算出来的progress
@@ -271,8 +264,243 @@ export default class CusVideo extends React.Component {
       this.props.videoback();
     }
   }
+  showController() {
+    this.setState({
+      show_controller: true
+      // needback: this.props.needback
+    });
+    this.bottomcontroller.setBottom(0);
+    this.topcontroller.setTop(0);
+  }
+  hideController() {
+    this.setState({
+      show_controller: false
+      // needback: false
+    });
+    this.bottomcontroller.setBottom(-50);
+    this.topcontroller.setTop(-50);
+  }
+}
+
+/**
+ * 将秒转换为 分:秒
+ * s int 秒数
+ */
+function formatTime(s) {
+  //计算分钟
+  //算法:将秒数除以60,然后下舍入,既得到分钟数
+  var h;
+  h = Math.floor(s / 60);
+  //计算秒
+  //算法:取得秒%60的余数,既得到秒数
+  s = Math.round(s % 60);
+  //将变量转换为字符串
+  h += "";
+  s += "";
+  //如果只有一位数,前面增加一个0
+  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) {
-  //计算分钟
-  //算法:将秒数除以60,然后下舍入,既得到分钟数
-  var h;
-  h = Math.floor(s / 60);
-  //计算秒
-  //算法:取得秒%60的余数,既得到秒数
-  s = Math.round(s % 60);
-  //将变量转换为字符串
-  h += "";
-  s += "";
-  //如果只有一位数,前面增加一个0
-  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}

+ 63 - 34
pages/components/SchedulePage.js

@@ -16,6 +16,8 @@ import {
   TouchableOpacity,
   ImageBackground,
   FlatList,
+  findNodeHandle,
+  UIManager,
   StatusBar,
   Button,
   DeviceEventEmitter
@@ -39,12 +41,14 @@ export default class SchedulePage extends BasePage {
     super(props);
     this.state = {
       statusbar_hidden: false,
+      video_show: false,
+      x: 0.0,
+      y: 0.0,
       videoImg_flex: 1,
-      videoImg_width: "100%",
-      videoImg_height: "100%",
-      video_flex: 0,
-      video_width: "0%",
-      video_height: "0%",
+      videoImage_width: 0,
+      videoImage_height: 0,
+      videoImage_x: 0.0,
+      videoImage_y: 0.0,
       video_uri:
         "http://efunvideo.ai160.com/vs2m/056/05602002/05602002001/05602002001.m3u8",
       title_height: "6%",
@@ -107,20 +111,11 @@ export default class SchedulePage extends BasePage {
                   "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1556277324856&di=dc1548a0c5ba10481af922e174912937&imgtype=0&src=http%3A%2F%2Fwww.51pptmoban.com%2Fd%2Ffile%2F2012%2F05%2F12%2F82c4568a90055adcf8fbb896f0841c69.jpg"
               }}
               style={{
-                flex: this.state.videoImg_flex,
-                width: this.state.videoImg_width,
-                height: this.state.videoImg_height
+                width: "100%",
+                height: "100%"
               }}
-            />
-            <CusVideo
-              uri={this.state.video_uri}
-              ref={view => (this.video = view)}
-              needback={false}
-              videofullScreenPlayer={this.fullScreenPlayer.bind(this)}
-              style={{
-                flex: this.state.video_flex,
-                width: this.state.video_width,
-                height: this.state.video_height
+              ref={c => {
+                this.video_image = c;
               }}
             />
           </View>
@@ -230,6 +225,22 @@ export default class SchedulePage extends BasePage {
             />
           </View>
         </View>
+        <CusVideo
+          show={this.state.video_show}
+          uri={this.state.video_uri}
+          ref={view => (this.video = view)}
+          needback={false}
+          videoback={() => alert("videoback")}
+          videofullScreenPlayer={this.fullScreenPlayer.bind(this)}
+          style={{
+            left: this.state.x,
+            top: this.state.y,
+            width: this.state.video_width,
+            height: this.state.video_height,
+            overflow: "hidden",
+            position: "absolute"
+          }}
+        />
       </View>
     );
   }
@@ -247,20 +258,28 @@ export default class SchedulePage extends BasePage {
     if (!this.state.isFull) {
       Orientation.lockToLandscape();
       this.setState({
-        title_height: "0%",
+        // title_height: "0%",
         video_frame_height: "100%",
-        seat_height: "0%",
-        flatlist_height: "0%",
+        // seat_height: "0%",
+        // flatlist_height: "0%",
         statusbar_hidden: true,
-        isFull: true
+        isFull: true,
+        x: 0,
+        y: 0,
+        video_width: "100%",
+        video_height: "100%"
       });
     } else {
       Orientation.lockToPortrait();
       this.setState({
-        title_height: "6%",
+        // title_height: "6%",
         video_frame_height: "32%",
-        seat_height: "2%",
-        flatlist_height: "60%",
+        // seat_height: "2%",
+        // flatlist_height: "60%",
+        x: this.state.videoImage_x,
+        y: this.state.videoImage_y,
+        video_width: this.state.videoImage_width,
+        video_height: this.state.videoImage_height,
         statusbar_hidden: false,
         isFull: false
       });
@@ -269,15 +288,25 @@ export default class SchedulePage extends BasePage {
   changeUrl(url) {
     //切换视频并且播放
     // alert(url);
-    this.setState({
-      videoImg_flex: 0,
-      videoImg_width: "0%",
-      videoImg_height: "0%",
-      video_flex: 1,
-      video_width: "100%",
-      video_height: "100%",
-      video_uri: url
-    });
+    const handle = findNodeHandle(this.video_image);
+    setTimeout(() => {
+      UIManager.measure(handle, (x, y, width, height, pageX, pageY) => {
+        console.warn(x, y, width, height, pageX, pageY);
+        this.setState({
+          x: pageX,
+          y: pageY,
+          video_width: width,
+          video_height: height,
+          videoImage_width: width,
+          videoImage_height: height,
+          videoImage_x: pageX,
+          videoImage_y: pageY,
+          video_show: true,
+          video_uri: url
+        });
+      });
+    }, 0);
+
     this.video.refreshVideo();
     this.video.start();
   }

+ 4 - 1
pages/components/SeekBar.js

@@ -7,8 +7,8 @@ import {
   Image,
   Button,
   PanResponder,
-  findNodeHandle,
   ImageBackground,
+  findNodeHandle,
   UIManager,
   DeviceEventEmitter
 } from "react-native";
@@ -196,6 +196,9 @@ export default class SeekBar extends BasePage {
       max: setmax
     });
   }
+  getMax() {
+    return this.state.max;
+  }
   setProgress(progress) {
     if (this.state.view_width > 0) {
       this.progress = progress;