react-native-video實現(xiàn)全屏播放

react-native-video 有全屏播放的方法 presentFullscreenPlayer曙博,但是使用的時候發(fā)現(xiàn)在安卓上全屏方法不好使,雖然可以人為的控制播放窗口大小為全屏怜瞒,視頻是能播放了父泳,但發(fā)現(xiàn)沒有可以控制播放的組件(暫停/播放按鈕,進(jìn)度條等)吴汪。仔細(xì)看文檔發(fā)現(xiàn)有這段說明:

Put the player in fullscreen mode.
On iOS, this displays the video in a fullscreen view controller with controls.
On Android ExoPlayer & MediaPlayer, this puts the navigation controls in fullscreen mode. It is not a complete fullscreen implementation, so you will still need to apply a style that makes the width and height match your screen dimensions to get a fullscreen video.

嘗試了好久還是搞不定惠窄,索性就自己定制播放的控制組件。

為了更好的體驗漾橙,我決定把播放器做成一個單獨全屏播放頁面杆融,當(dāng)點擊播放視頻的時候,直接跳轉(zhuǎn)到播放器頁面霜运,頁面上有關(guān)閉按鈕脾歇,而且安卓上播放頁面點擊回退可以返回剛剛的頁面,比較符合邏輯淘捡。之前我把跳轉(zhuǎn)播放前的頁面和播放組件放同一個頁面藕各,點擊播放時,設(shè)置播放組件全屏可見并把其他內(nèi)容藏起來焦除。但是這樣做有些復(fù)雜激况,而且很難隱藏頁面的狀態(tài)欄和標(biāo)題欄,點擊返回時會回退到上一個頁面膘魄,可能用戶此時只是想退出播放乌逐,回到播放前的頁面。

播放和暫停功能比較容易创葡,圖標(biāo)可以使用 react-native-vector-icons 上的圖標(biāo)浙踢。因為項目使用的是 antd-mobile-rn 的 UI 庫,所以播放進(jìn)度條可以直接使用現(xiàn)成的組件 Slider蹈丸,拖動進(jìn)度條時根據(jù)進(jìn)度條位置重新設(shè)置播放進(jìn)度可以簡單的實現(xiàn)播放進(jìn)度控制(this.player.seek(value))成黄,這里用 this.state.paused 控制視頻的播放和暫停。

關(guān)于橫屏播放逻杖,項目暫時沒有這個需求,為節(jié)省時間思瘟,這里也不深究荸百,可以參考一下這里。最后展示一下效果

react-native-video1.png
react-native-video1.pn2.png

詳細(xì)代碼如下:

import * as React from "react";
import {
  View,
  Text,
  StatusBar,
  SafeAreaView,
  Platform,
  TouchableOpacity,
  ViewStyle,
  TextStyle,
  StyleSheet
} from "react-native";
import { Toast, ActivityIndicator, Slider } from "antd-mobile-rn";
import MaterialsIcon from "react-native-vector-icons/MaterialIcons";
import Video from "react-native-video";
import * as _ from "lodash";
import { size, color } from "../../config";

export default class VideoPlayer extends React.Component<any, any> {
  static navigationOptions = ({ navigation }: any) => ({
    header: null
  });

  player: any;
  constructor(props: IVideoPlayerProps) {
    super(props);
    this.state = {
      onLoading: false,
      videoHeight: size.height,
      playerIconVisible: true,
      paused: true,
      playableDuration: 0,
      currentTime: 0,
      progressPercent: 0
    };
  }

  render() {
    // videoSource: { uri: 'http://cdn.xxx.com/assets/videos/xxx.mp4' } OR require('../../local.mp4')
    const videoSource = _.get(this.props.navigation, "state.params.source");
    let sourceType = _.get(
      this.props.navigation,
      "state.params.sourceType",
      "url"
    );
    if (!videoSource || (sourceType === "url" && !videoSource.uri)) {
      Toast.fail("視頻路徑不正確滨攻!", 2);
      return <SafeAreaView style={indicatorStyles.container} />;
    }
    return (
      <SafeAreaView style={indicatorStyles.container}>
        <Video
          style={{ width: size.width, height: this.state.videoHeight }}
          source={videoSource}
          ref={(ref: any) => (this.player = ref)}
          paused={this.state.paused}
          onLoadStart={(e: any) => {
            console.log("onLoadStart: ", e);
            this.setState({ onLoading: true });
          }}
          onEnd={() =>
            this.setState({ playerIconVisible: true, onLoading: false })
          }
          onError={() => {
            Toast.fail("加載視頻出錯", 2);
            this.setState({ onLoading: false });
          }}
          onLoad={(e: any) => {
            console.log("onLoad && ready to play: ", e);
            this.setState({ paused: true, onLoading: false });
            const height = _.get(e, "naturalSize.height");
            const width = _.get(e, "naturalSize.width");
            console.log("video' width &&  height: ", width, height);
            let videoHeight = this.state.videoHeight;
            if (_.isNumber(height) && _.isNumber(width)) {
              videoHeight = (size.width * height) / width;
            }
            this.setState({
              playableDuration: _.get(e, "duration", 0),
              videoHeight: videoHeight,
              paused: false
            });
          }}
          onProgress={(e: any) => {
            // console.log('onProgress: ', e);
            let currentTime = _.get(e, "currentTime", 0);
            let playableDuration = _.get(e, "playableDuration", 1);
            this.setState({
              currentTime,
              progressPercent: (currentTime / playableDuration) * 100
            });
          }}
          onFullscreenPlayerDidPresent={() => {
            this.setState({ paused: false });
          }}
          onFullscreenPlayerWillDismiss={() => {
            this.setState({ paused: true });
          }}
        />

        <TouchableOpacity
          style={indicatorStyles.videoCover}
          onPress={async () => {
            await this.setState((prevState: any) => ({
              playerIconVisible: !prevState.playerIconVisible
            }));
            if (!this.state.paused && this.state.playerIconVisible) {
              setTimeout(() => {
                this.setState({ playerIconVisible: false });
              }, 3000);
            }
          }}
        >
          {this.state.onLoading && <ActivityIndicator color="#fff" />}

          <TouchableOpacity
            style={{
              position: "absolute",
              top: Platform.OS === "ios" ? 0 : StatusBar.currentHeight,
              right: 0,
              padding: 10
            }}
            onPress={() => this.props.navigation.goBack()}
          >
            <MaterialsIcon
              name="close"
              size={30}
              color={"rgba(255, 255, 255, 0.8)"}
            />
          </TouchableOpacity>

          {this.state.playerIconVisible && (
            <View style={indicatorStyles.playerController}>
              <TouchableOpacity
                style={indicatorStyles.playerIcon}
                onPress={() => {
                  this.setState((prevState: any) => ({
                    paused: !prevState.paused
                  }));
                }}
              >
                <MaterialsIcon
                  name={this.state.paused ? "play-arrow" : "pause"}
                  size={30}
                  color={"rgba(255, 255, 255, 0.8)"}
                />
              </TouchableOpacity>
              <Text style={indicatorStyles.playerTime}>
                {this.state.currentTime}
              </Text>
              <View style={indicatorStyles.playerProgress}>
                <Slider
                  value={this.state.currentTime}
                  min={0}
                  max={this.state.playableDuration}
                  onChange={(value: number) => {
                    this.player.seek(value);
                    this.setState({ paused: false });
                  }}
                  onAfterChange={(value: number) =>
                    console.log("afterChange: ", value)
                  }
                />
              </View>
              <Text style={indicatorStyles.playerTime}>
                {this.state.playableDuration}
              </Text>
            </View>
          )}
          <View />
        </TouchableOpacity>
      </SafeAreaView>
    );
  }
}

const PLAYER_ICON_WIDTH = 30;
const PLAYER_TIME = 50;
const PROGRESS_WIDTH = size.width - PLAYER_ICON_WIDTH - PLAYER_TIME * 2 - 10;
const style = {
  container: {
    flex: 1,
    backgroundColor: "#000",
    alignItems: "center",
    justifyContent: "center"
  },
  videoCover: {
    position: "absolute",
    width: "100%",
    height: "100%",
    backgroundColor: "transparent",
    alignItems: "center",
    justifyContent: "center"
  },
  playerController: {
    flexDirection: "row",
    position: "absolute",
    bottom: 5,
    left: 0,
    width: "100%",
    backgroundColor: "rgba(0,0,0,0.3)",
    alignItems: "center"
  },
  playerIcon: {
    width: PLAYER_ICON_WIDTH,
    height: 30,
    marginLeft: 10,
    justifyContent: "center",
    alignItems: "center"
  },
  playerProgress: {
    justifyContent: "center",
    height: 4,
    width: PROGRESS_WIDTH,
    flex: 1
  },
  playerTime: {
    width: PLAYER_TIME,
    height: 30,
    color: "#fff",
    padding: 5,
    textAlign: "center"
  }
};
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末够话,一起剝皮案震驚了整個濱河市蓝翰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌女嘲,老刑警劉巖畜份,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異欣尼,居然都是意外死亡爆雹,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門愕鼓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來钙态,“玉大人,你說我怎么就攤上這事菇晃〔岬梗” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵磺送,是天一觀的道長驻子。 經(jīng)常有香客問我,道長估灿,這世上最難降的妖魔是什么拴孤? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮甲捏,結(jié)果婚禮上演熟,老公的妹妹穿的比我還像新娘。我一直安慰自己司顿,他們只是感情好芒粹,可當(dāng)我...
    茶點故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著大溜,像睡著了一般化漆。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上钦奋,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天座云,我揣著相機(jī)與錄音,去河邊找鬼付材。 笑死朦拖,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的厌衔。 我是一名探鬼主播璧帝,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼富寿!你這毒婦竟也來了睬隶?” 一聲冷哼從身側(cè)響起锣夹,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎苏潜,沒想到半個月后银萍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡恤左,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年贴唇,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片赃梧。...
    茶點故事閱讀 38,137評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡滤蝠,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出授嘀,到底是詐尸還是另有隱情物咳,我是刑警寧澤,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布蹄皱,位于F島的核電站览闰,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏巷折。R本人自食惡果不足惜压鉴,卻給世界環(huán)境...
    茶點故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望锻拘。 院中可真熱鬧油吭,春花似錦、人聲如沸署拟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽推穷。三九已至心包,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間馒铃,已是汗流浹背蟹腾。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留区宇,地道東北人娃殖。 一個月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像萧锉,于是被迫代替她去往敵國和親珊随。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,901評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 1柿隙、通過CocoaPods安裝項目名稱項目信息 AFNetworking網(wǎng)絡(luò)請求組件 FMDB本地數(shù)據(jù)庫組件 SD...
    陽明先生_x閱讀 15,968評論 3 119
  • 躺在床上在感嘆叶洞,都不知道今天怎么過來的,一天又過去了禀崖。 室友在一邊打趣我說衩辟,你記得哪天是怎么過來的? 于是波附,炮轟開...
    zerooo閱讀 295評論 6 2
  • 她說有的人變成了學(xué)霸有的人變成了文藝青年有的人變成了土豪有的人變成了男神女神而又有的人變成了段子狗 。那個現(xiàn)在是學(xué)...
    圣誕老人叫瓦斯哥閱讀 1,720評論 0 4
  • 春秋之社會仅财,周禮衰敗狈究,社稷動搖。始有諸子立說盏求,百家興起抖锥。探天下動亂之根源,解庶民于水深火熱之中碎罚。 ...
    陳年風(fēng)流閱讀 753評論 3 2
  • 最近室友老是抱怨自己怎么還沒有男朋友怎么還是單身狗一枚磅废。我也有同樣的困惑,到底是什么導(dǎo)致了我們畢業(yè)...
    旅途在前閱讀 236評論 0 0