欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > > 内容正文

Android Flutter控件封装之视频进度条的实现,

来源: 开发者 投稿于  被查看 22874 次 评论:142

Android Flutter控件封装之视频进度条的实现,


目录
  • 一、基本的效果展示
  • 二、具体使用和相关属性介绍
    • 1、具体使用
    • 2、相关属性
  • 三、控制器封装考虑因素
    • 1、基本的UI设定
    • 2、拖动进度的实现
    • 3、时间的换算和进度的绑定
    • 4、定时器的控制
  • 四、控制器部分功能代码刨析
    • 1、基本的布局
    • 2、时间转换
    • 3、定时操作
  • 五、总结及源码地址

    视频控制器,三方所提供的样式,有时很难满足我们的需求,对于此情况,我们不得不在此基础上自行封装,今天所分享的文章就是一个很简单的控制器封装案例,包含了基本的播放暂停,全屏和退出全屏,以及时间和进度的展示,封装了事件回调以及各个属性的控制,基本上可以满足大部分的业务需求,即便不满足,大家也可以在此基础之上拓展。

    我们还是按照惯例,简单罗列一个大纲:

    1、基本的效果展示

    2、具体使用和相关属性介绍

    3、控制器封装考虑因素

    4、控制器部分功能代码刨析

    5、总结及源码地址

    一、基本的效果展示

    具体的效果,没什么好说的,都是大众常见的样式,依次从左到右为:播放暂停按钮,播放时间,播放进度,总的时间,全屏及退出全屏按钮。

    可以实现的功能有,图标的动态设置,时间进度的颜色及大小控制,以及定时器的开启,具体的可以看第二项。

    二、具体使用和相关属性介绍

    1、具体使用

    作为一个Widget,大家可以随意使用,单独亦或者和视频播放器绑定使用。

    VipVideoController(
            totalTime: 1000 * 60,
            backgroundColor: Colors.red,
            progressColor: Colors.amber,
            thumbColor: Colors.red,
            textStyle: TextStyle(color: Colors.red),
            onVideoPlayClick: (isPlay) {
              print("当前播放按钮状态$isPlay");
            },
            onVideoFullScreenClick: (isFullScreen) {
              print("当前全屏按钮状态$isFullScreen");
            },
            onVideoChanged: (position) {
              //返回毫秒
              print("当前拖拽的进度$position");
            }
          )

    2、相关属性

    属性类型概述
    heightdouble设置控制器高度
    progressHeightdouble进度条高度
    videoPlayIconString视频播放Icon
    videoPauseIconString视频暂停Icon
    videoFullScreenIconString视频全屏Icon
    videoExitFullScreenIconString退出全屏Icon
    textStyleTextStyle文本样式
    backgroundColorColor背景颜色
    progressColorColor进度颜色
    thumbColorColor拖动颜色
    thumbRadiusdoublethumb大小
    playTimeMarginLeftdouble播放时间距离左边的距离
    playTimeMarginRightdouble播放时间距离右边的距离
    videoTimeMarginLeftdouble视频时间距离左边的距离
    videoTimeMarginRightdouble视频时间距离右边的距离
    totalTimeint总时长
    changeTimeint改变时长
    isTimerbool是否需要定时
    onVideoPlayClickValueChanged<bool>视频播放点击
    onVideoFullScreenClickValueChanged<bool>视频全屏点击点击
    onVideoChangedValueChanged<int>滑动回调
    onVideoChangeStartValueChanged<int>拖动开始
    onVideoChangeEndValueChanged<int>拖动结束
    isPlayedbool播放控制状态,暂停还是开始
    isFullScreenbool是否是全屏

    三、控制器封装考虑因素

    视频控制器虽然说简单,但需要考虑的因素还是比较多的,比如点击播放和暂停,全屏和退出全屏的事件回调,拖动进度除了更改自身进度也要更改时间进度,传递的时间换算,定时的开启和关闭等等都是需要解决的。

    1、基本的UI设定

    控制器的UI一定是基于设计同学所定的UI稿,否则就要以技术驱动设计更改,一般很难,不过也有特殊的案例存在。所以在封装的时候,要么基于UI稿,要么就是动态可配置,通过属性更改基本的样式或者位置。

    2、拖动进度的实现

    拖动进度就比较简单了,使用的是原生提供的Slider,也就是滑杆,类似于Android中的SeekBar,需要注意的是,颜色等属性的动态配置。

    3、时间的换算和进度的绑定

    时间的换算,需要把传入的时间戳,转化为我们所需要的时间格式,也就是时分秒的格式,这里使用了intl国际化的插件,主要用到到格式转换DateFormat。

    4、定时器的控制

    定时器很简单,实例化一个Timer即可,但是,什么时候开始,什么时候暂停都是我们需要考虑的,一般情况下,直接和视频播放器进行绑定,直接更改进度即可,就不用这个定时,如果要用,可以用一个属性控制;在需要定时的情况下,点击暂停,需要暂停定时,除此之外播放完毕后也需要暂停定时;当拖动完毕后,需要开启定时,点击播放,也需要开启定时,所以,对于定时器控制这一块,一定要缕清楚。

    四、控制器部分功能代码刨析

    1、基本的布局

    很简单,一个横向的组件Row,包裹了5个子组件,进度条使用Expanded,用于占有剩余的空间。

     return SizedBox(
            height: widget.height,
            child: Row(
              children: [
                getPlayIcon(), //开始和暂停
                getPlayTime(timeStampToStringDate(_progress)), //时间
                Expanded(child: getSliderTheme()), //进度
                getVideoTime(timeStampToStringDate(widget.totalTime!)), //时间
                getFullScreenIcon() //全屏
              ],
            ));

    播放Icon和全屏Icon

    未传Icon情况下,直接使用默认的Icon,如果传递了,那么直接使用传递的,需要根据播放状态展示播放按钮还是暂停按钮,全屏Icon需要根据是否全屏状态,来展示对应的图标,同时回调点击事件,VipImage是之前封装的图片组件,大家可以查看以往的分享。

      /*
      * 获取播放Icon
      * */
      Widget getPlayIcon() {
        if (widget.videoPlayIcon == null) {
          return InkWell(
            onTap: onPlayClick,
            child: Icon(_isPlayed ? Icons.pause : Icons.play_arrow),
          );
        } else {
          return VipImage(
            _isPlayed ? widget.videoPlayIcon : widget.videoPauseIcon,
            onClick: onPlayClick,
          );
        }
      }
    /*
      * 获取全屏Icon
      * */
      Widget getFullScreenIcon() {
        if (widget.videoFullScreenIcon == null) {
          return InkWell(
            onTap: onFullScreenClick,
            child: Icon(_isFullScreen ? Icons.fullscreen_exit : Icons.fullscreen),
          );
        } else {
          return VipImage(
            _isFullScreen
                ? widget.videoFullScreenIcon
                : widget.videoExitFullScreenIcon,
            onClick: onFullScreenClick,
          );
        }
      }

    播放时长和总时长

    VipText是之前封装的文本组件,大家可以查看以往的分享,需要注意的是传入的时间需要格式化处理,转化为对应的时分秒结构。

      /*
       *获取播放时长
       * */
      Widget getPlayTime(String text) {
        return VipText(
          text,
          style: widget.textStyle,
          marginLeft: widget.playTimeMarginLeft,
          marginRight: widget.playTimeMarginRight,
        );
      }
     /*
       *获取总的播放时长
       * */
      Widget getVideoTime(String text) {
        return VipText(
          text,
          style: widget.textStyle,
          marginLeft: widget.videoTimeMarginLeft,
          marginRight: widget.videoTimeMarginRight,
        );
      }

    中间的进度条

    进度条使用的是Slider,直接按照原生的Api使用即可,需要注意,最大的进度也就是max,需要和设置的总时长绑定,还有divisions分段,需要以秒作为区分,否则在滑动改变的时候,有可能会和定时造成冲突。

    Widget getSliderTheme() {
        var divisions = widget.totalTime! / 1000;
        return SliderTheme(
          data: SliderThemeData(
              //高度
              trackHeight: widget.progressHeight,
              //去掉长按光晕
              overlayColor: Colors.transparent,
              //背景颜色
              inactiveTrackColor: widget.backgroundColor,
              activeTrackColor: widget.progressColor,
              thumbColor: widget.thumbColor,
              thumbShape:
                  RoundSliderThumbShape(enabledThumbRadius: widget.thumbRadius)),
          child: Slider(
            min: 0,
            max: widget.totalTime!.toDouble(),
            value: _progress.toDouble(),
            divisions: divisions.toInt(),
            onChangeStart: (progress) {
              if (widget.onVideoChangeStart != null) {
                widget.onVideoChangeStart!(progress.toInt());
              }
            },
            onChangeEnd: (progress) {
              if (widget.onVideoChangeEnd != null) {
                widget.onVideoChangeEnd!(progress.toInt());
              }
              if (_isPlayed) {
                //播放状态下,如果定时,才会执行
                _startTimer();
              }
            },
            onChanged: (double value) {
              setState(() {
                _progress = value.toInt();
              });
              //回调当前进度
              if (widget.onVideoChanged != null) {
                widget.onVideoChanged!(_progress);
              }
            },
          ),
        );
      }

    2、时间转换

    前边有说过使用的是intl国际化插件,主要用到的是dateFormat.format()。

      /*
      * 时间戳转换时间
      * */
      String timeStampToStringDate(int time) {
        String format = time < 1000 * 60 * 60 ? TimeUtil.m_s : TimeUtil.h_m_s;
        return TimeUtil.getTimeStampToStringDate(time, format: format);
      }
      /*
      * 时间戳转时间
      * */
      static String getTimeStampToStringDate(int timeStamp,
          {String format = y_M_d}) {
        var dateFormat = DateFormat(format);
        var dateTime = DateTime.fromMillisecondsSinceEpoch(timeStamp);
        return dateFormat.format(dateTime);
      }

    3、定时操作

    定时需要注意的是,在需要定时的时候再开启,比如定义的属性为true时,就执行开启动作,当开启定时后,我们的进度大于总时长时,就需要暂停定时。

    开启定时场景:1、定义的属性为true时,进入直接开启定时。2、当点击开始播放按钮时,如果使用定时,就要开启,3、当播放完毕后,再次拖动,也需要开启定时。

    暂停定时场景:1、点击暂停视频时,关闭定时,2、播放结束时,关闭定时,3、页面销毁时,也需要关闭定时。

    /*
      * 开启定时
      * */
      void _startTimer() {
        if (widget.isTimer! && _timer == null) {
          //开启定时,一秒执行一次
          _timer = Timer.periodic(const Duration(seconds: 1), (timer) {
            if (_progress >= widget.totalTime!) {
              _pauseTimer();
            } else {
              setState(() {
                _progress += 1000;
              });
              widget.onVideoChanged!(_progress);
            }
          });
        }
      }
      /*
      * 暂停定时
      * */
      void _pauseTimer() {
        if (_timer != null) {
          _timer!.cancel(); //取消计时器
          _timer = null;
        }
      }

    五、总结及源码地址

    源码是一个简单的文件,地址:github.com/AbnerMing888/flutter_widget/blob/master/lib/ui/widget/vip_video_controller.dart

    源码中有用到之前封装的组件,请大家悉知,目前所封装的组件,样式和图标都是可以更换的,但是有一个就是位置还有组件是否显示没有封装,不过源码已经贴出,大家可以在源码基础之上进行更改。

    以上就是Android Flutter控件封装之视频进度条的实现的详细内容,更多关于Android Flutter视频进度条的资料请关注3672js教程其它相关文章!

    您可能感兴趣的文章:
    • Android自定义SeekBar实现视频播放进度条
    • Flutter质感设计之进度条
    • Flutter 实现进度条效果
    • flutter轮子计划之进度条
    • Android自定义view实现圆环进度条效果
    • Android ProgressBar实现进度条效果

    用户评论