flutter开发仿抖音首页面上下滑动切换播放视频效果

题记
—— 执剑天涯,从你的点滴积累开始,所及之处,必精益求精,即是折腾每一天。

-----【视频教程 感兴趣的伙伴可以瞅瞅】


本小节讲述:
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) => 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 的使用案例

我们将上述 【构建 TabBarView】 处代码替换,使用 PageView 来构建 上下整屏页面切换效果


  ///构建 TabBarView
  buildTableViewWidget() {
    return TabBarView(
      controller: tabController,
      children: tabTextList
          .map((value) => 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函数中初始化的


  ///推荐模拟数据
  List <VideoModel> videoList =[];
  ///关注模拟数据
  List <VideoModel> videoList2 =[];

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

   ...

    ///创建模拟数据

    for (int i = 0; i < 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 < 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 就可实现播放进度的进度条绘制。


完毕

基于 Flutter 3.x 进行仿抖音跨平台混合开发,是一种使用最新版本的Flutter框架来开发类似抖音的应用程序的方法。 Flutter是一种跨平台的开发框架,可以让开发者使用同一套代码同时在iOS和Android平台上构建高性能的应用程序。它提供了丰富的UI组件和工具,使开发过程更加简单和高效。 要实现仿抖音的跨平台混合开发,首先需要对抖音的功能和界面进行分析和设计。然后,使用Flutter框架来实现这些功能和界面。 Flutter提供了丰富的UI组件,如按钮、文本、图片、视频播放等,可以用于构建抖音的各种界面元素。开发者可以使用Dart语言来编写业务逻辑,同时可以使用Flutter提供的hot reload功能实时预览和调试应用程序。 为了实现跨平台开发开发者可以使用Flutter的多平台支持。Flutter可以生成原生的iOS和Android应用程序,以及Web和桌面应用程序。这使得开发者可以在不同的平台上发布和部署仿抖音的应用程序。 在开发过程中,开发者可以使用Flutter的插件来集成各种第三方功能和服务,如视频播放、数据存储、社交分享等。这些插件可以帮助开发者更加方便地实现仿抖音的各种功能。 总之,基于Flutter 3.x进行仿抖音跨平台混合开发,是一种高效、灵活的开发方法。通过使用Flutter框架和相关工具,开发者可以快速构建出功能完善、界面精美的仿抖音应用程序,并在多个平台上进行发布和部署。
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

早起的年轻人

创作源于分享

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值