flutter開發仿抖音首頁面上下滑動切換播放視頻效果

題記 —— 執劍天涯,從你的點滴積累開始,所及之處,必精益求精,便是折騰每一天。java

重要消息git


> 本小節講述: > 1 VideoPlayer 視頻播放組件使用 > 2 VideoPlayerController 的使用分析 > 3 FutureBuilder 的使用分析 > 4 PageView構建上下滑動的整屏切換頁面 > 5 TabBar 與 TabBarView 構建左右滑動切換的頁面緩存

在這裏插入圖片描述

1 首先咱們來實現頁面的主體部分

經過 TabBar 與 TabBarView 實現左右切換的頁面網絡

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

class MainFind3Page extends StatefulWidget {
  @override
  State<statefulwidget> createState() {
    return MainFindPage3State();
  }
}

class MainFindPage3State extends State with SingleTickerProviderStateMixin {
  
  List<string> tabTextList = ["關注", "推薦"];
  List<tab> tabWidgetList = [];
  TabController tabController;

  @override
  void initState() {
    super.initState();

    for (var value in tabTextList) {
      tabWidgetList.add(Tab(
        text: "$value",
      ));
    }
    tabController = new TabController(length: tabTextList.length, vsync: this);
  }

  @override
  Widget build(BuildContext context) {
    return buildRootBody();
  }

  Widget buildRootBody() {
    return Scaffold(
      body: Stack(
        children: <widget>[
          Positioned(
            left: 0,
            right: 0,
            top: 0,
            bottom: 0,
            child: Container(
              color: Colors.black,
            ),
          ),
          Positioned(
            left: 0,
            right: 0,
            top: 0,
            bottom: 0,
            child: buildTableViewWidget(),
          ),
          Positioned(
            left: 0,
            right: 0,
            bottom: 0,
            top: 54,
            child: buildTabBarWidget(),
          ),
        ],
      ),
    );
  }
  ///構建 TabBarView
  buildTableViewWidget() {
    return TabBarView(
      controller: tabController,
      children: tabTextList
          .map((value) =&gt; Container(
                alignment: Alignment.center,
                child: Text("$value",style: TextStyle(color: Colors.white),),
              ))
          .toList(),
    );
  }
  ///構建頂部標籤部分
  buildTabBarWidget() {
    return Container(
      ///對齊在頂部中間
      alignment: Alignment.topCenter,
      child: TabBar(
        controller: tabController,
        tabs: tabWidgetList,
        ///指示器的顏色
        indicatorColor: Colors.white,
        ///指示器的高度
        indicatorWeight: 2.0,
        isScrollable: true,

        ///指示器的寬度與文字對齊
        indicatorSize: TabBarIndicatorSize.label,
      ),
    );
  }
}

在這裏是經過 幀佈局 將 TabBar 與 TabBarView 疊在一塊兒的。 效果以下 在這裏插入圖片描述異步

2 經過 PageView 來實現上下整屏切換效果

文章《flutter跨平臺開發一點一滴分析系列文章》中 1.3.3 有記錄 PageView 的使用案例ide

咱們將上述 【構建 TabBarView】 處代碼替換,使用 PageView 來構建 上下整屏頁面切換效果函數

///構建 TabBarView
  buildTableViewWidget() {
    return TabBarView(
      controller: tabController,
      children: tabTextList
          .map((value) =&gt; buildTableViewItemWidget(value))
          .toList(),
    );
  }
   /// 用來建立上下滑動的頁面
  Widget buildTableViewItemWidget(String value) {

    List<videomodel> list =[];
    if(value == "推薦"){
      list= videoList;
    }else{
      list = videoList2;
    }
    return PageView.builder(
      /// pageview中 子條目的個數
      itemCount:list.length ,
      /// 上下滑動
        scrollDirection: Axis.vertical,
        itemBuilder: (BuildContext context,int index){
          VideoModel videoModel = list[index];
      return buildPageViewItemWidget(value,videoModel);
    });
  }

這裏面用到了 videoList 與 videoList2,保存的數據模型,是在 initState函數中初始化的oop

///推薦模擬數據
  List <videomodel> videoList =[];
  ///關注模擬數據
  List <videomodel> videoList2 =[];

  @override
  void initState() {
    super.initState();

   ...

    ///建立模擬數據

    for (int i = 0; i &lt; 10; i++) {
      VideoModel videoModel = new VideoModel();
      videoModel.videoName = "推薦測試數據$i";
      videoModel.pariseCount = i * 22;
      if (i % 3 == 0) {
        videoModel.isAttention = true;
        videoModel.isLike = true;
      } else {
        videoModel.isAttention = false;
        videoModel.isLike = false;
      }
      videoModel.videoImag ="";
      videoModel.videoUrl ="";
      videoList.add(videoModel);
    }

    for (int i = 0; i &lt; 3; i++) {
      VideoModel videoModel = new VideoModel();
      videoModel.videoName = "關注測試數據$i";
      videoModel.pariseCount = i * 22;
      videoModel.isAttention = true;
      if (i % 3 == 0) {
        videoModel.isLike = true;
      } else {
        videoModel.isLike = false;
      }
      videoModel.videoImag ="";
      videoModel.videoUrl ="";
      videoList2.add(videoModel);
    }
  }

對於 VideoModel 來說,就是咱們保存視頻信息的數據模型了佈局

class VideoModel {
  ///視頻名稱
  String videoName ='';
  ///視頻連接
  String videoUrl ='';
  ///視頻截圖
  String videoImag ='';
  ///是否關注
  bool isAttention =false;
  ///關注的個數
  num attentCount =0;
  ///是否喜歡
  bool isLike = false;
  ///點讚的個數
  num pariseCount = 0;
  ///分享的次數
  num shareCount=0;
}

在上述代碼中咱們也使用到了 buildPageViewItemWidget 函數,以下測試

buildPageViewItemWidget(String value, VideoModel videoModel) {
    return FindVideoItemPage(value,videoModel);
  }

在這裏直接構建 的 FindVideoItemPage ,看以下 FindVideoItemPage 的定義

///播放視頻的頁面
class FindVideoItemPage extends StatefulWidget {
  String tabValue;
  VideoModel videoModel;
  FindVideoItemPage(this.tabValue, this.videoModel);

  @override
  State<statefulwidget> createState() {
    return FindVideoItemPageState();
  }
}

class FindVideoItemPageState extends State<findvideoitempage> {
  ///建立視頻播放控制 器
  VideoPlayerController videoPlayerController;
  ///控制更新視頻加載初始化完成狀態更新
  Future videoPlayFuture;

  @override
  void initState() {
    super.initState();

    videoPlayerController =
        VideoPlayerController.network(widget.videoModel.videoUrl);

    videoPlayFuture = videoPlayerController.initialize().then((_) {
      ///視頻初始完成後
      ///調用播放
      videoPlayerController.play();
      setState(() {});
    });
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <widget>[
        ///播放視頻
        buildVideoWidget(),

        ///控制播放視頻按鈕
        buildControllWidget(),

        ///底部區域的視頻介紹
        buildBottmFlagWidget(),

        ///右側的用戶信息按鈕區域
        buildRightUserWidget(),
      ],
    );
  }

  @override
  void dispose() {
    super.dispose();
    videoPlayerController.dispose();
  }

}

其實 FindVideoItemPage 就是咱們 PageView 中構建的子視圖了,咱們能夠看到 在 初始化函數 initState 中 建立了 VideoPlayerController,顧名思義 VideoPlayerController 是用來控制當前頁面視頻的播放的,在 dispose 中銷燬 VideoPlayerController,這個也好理解,就是當前頁面都釋放掉了,播放的視頻固然要中止播放了。

在這裏這建立了一個 videoPlayFuture ,是用來監聽 VideoPlayerController 初始化狀態的,結合 FutureBuilder 來實時更新頁面 State,如在方法 buildVideoWidget() 中

///播放視頻
  buildVideoWidget() {
    return FutureBuilder(
      future: videoPlayFuture,
      builder: (BuildContext contex, value) {
        if (value.connectionState == ConnectionState.done) {
          ///點擊事件
          return InkWell(
            onTap: () {
              if (videoPlayerController.value.initialized) {
                /// 視頻已初始化
                if (videoPlayerController.value.isPlaying) {
                  /// 正播放 --- 暫停
                  videoPlayerController.pause();
                } else {
                  ///暫停 ----播放
                  videoPlayerController.play();
                }

                setState(() {});
              } else {
                ///未初始化
                videoPlayerController.initialize().then((_) {
                  videoPlayerController.play();
                  setState(() {});
                });
              }
            },

            ///居中
            child: Center(
              /// AspectRatio 組件用來設定子組件寬高比
              child: AspectRatio(
                ///設置視頻的大小 寬高比。長寬比表示爲寬高比。例如,16:9寬高比的值爲16.0/9.0
                aspectRatio: videoPlayerController.value.aspectRatio,
                ///播放視頻的組件
                child: VideoPlayer(videoPlayerController),
              ),
            ),
          );
        } else {
          return Container(
            alignment: Alignment.center,
            ///圓形加載進度
            child: CircularProgressIndicator(),
          );
        }
      },
    );
  }

FutureBuilder會依賴一個Future,對於FutureBuilder來說

FutureBuilder({
  this.future,
  this.initialData,
  @required this.builder,
})

future ,FutureBuilder 中依賴的 Future ,一般是一個異步耗時任務,如這裏的 videoPlayFuture 是指向 videoPlayerController 的初始化函數initialize(),這是一個異步的耗時操做, builder ,Widget構建器,該構建器會在Future執行的不一樣階段被屢次調用,構建格式以下

Function (BuildContext context, AsyncSnapshot snapshot)
  /**
   * snapshot會包含當前異步任務的狀態信息及結果信息 ,
   * 好比咱們能夠經過snapshot.connectionState獲取異步任務的狀態信息、
   * 經過snapshot.hasError判斷異步任務是否有錯誤等等
   */

而經過 snapshot.connectionState 獲取的 ConnectionState 狀態有如下值:

enum ConnectionState {
  /// 當前沒有異步任務,好比[FutureBuilder]的[future]爲null時
  none,
  /// 異步任務處於等待狀態
  waiting,
  /// Stream處於激活狀態(流上已經有數據傳遞了),對於FutureBuilder沒有該狀態。
  active,
  /// 異步任務已經終止.
  done,
}
3 經過 VideoPlayer 播放視頻

使用 VideoPlayer,咱們首先須要添加依賴

video_player: ^0.6.4

對於 VideoPlayer 來說,它只接收一個 VideoPlayerController,咱們能夠經過 VideoPlayerController 來綁定要播放的視頻地址

///網絡連接
    videoPlayerController = VideoPlayerController.network(widget.videoModel.videoUrl);
    ///本地連接
    VideoPlayerController videoPlayerController2 = VideoPlayerController.asset(widget.videoModel.videoUrl);
    ///File形式的視頻
    VideoPlayerController videoPlayerController3 = VideoPlayerController.file(File(widget.videoModel.videoUrl));

當 綁定了播放的地址後,能夠VideoPlayerController來預加載初始化播放器

videoPlayerController.initialize().then((_) {
      ///視頻初始完成後
      ///調用播放
      videoPlayerController.play();
      setState(() {});
    });

對於 initialize() 方法來說,這是一個異步的耗時操做.

VideoPlayerValue 記錄了當前視頻播放的一些狀態信息

VideoPlayerValue videoPlayerValue = videoPlayerController.value;


///是否初始化完成
bool initialized = videoPlayerValue.initialized;
///是否正在播放
bool isPlaying = videoPlayerValue.isPlaying;
///當前播放的視頻的寬高比例
double aspectRatio = videoPlayerValue.aspectRatio;
///當前視頻是否緩存 
bool  isBuffer = videoPlayerValue.isBuffering;
///當前視頻是否循環
bool isLoop = videoPlayerValue.isLooping;
///當前播放視頻的總時長
Duration totalDuration = videoPlayerValue.duration;
///當前播放視頻的位置 
Duration currentDuration = videoPlayerValue.position;

在這裏,咱們經過 totalDuration 與 currentDuration 就可實現播放進度的進度條繪製。


完畢</widget></findvideoitempage></statefulwidget></videomodel></videomodel></videomodel></widget></tab></string></statefulwidget>

相關文章
相關標籤/搜索