Flutter 2进阶(九):FijkPlayer播放视频与卡片效果

使用 FijkPlayer 播放视频,包括的功能:亮度调节,音量调节,长按2倍速播放,双击暂停/开始,全屏播放。大概的效果图:

下载链接:

优快云 :flutter_blbl.zip-Android文档类资源-优快云下载

GitHub:https://github.com/wuqingsen/FlutterLearnDemo

用到的插件,网格布局,图片加载缓存淡入效果,视频播放器,音量和亮度控制器:

  flutter_staggered_grid_view: ^0.4.1
  transparent_image: ^2.0.0
  cached_network_image: ^2.5.0
  fijkplayer: ^0.10.1
  volume_controller: ^2.0.2
  screen_brightness: ^0.0.2

卡片效果:

封装了一个 video_card.dart :

import 'package:flutter/material.dart';
import 'package:flutter_blbl/model/base/stateful_widget_base.dart';
import 'package:flutter_blbl/model/bean/home_page_bean.dart';
import 'package:flutter_blbl/model/navigator/my_navigator.dart';
import 'package:flutter_blbl/utils/view_util.dart';

class VideoCard extends BaseWidget {
  final HomePageBean homePageBean;

  VideoCard({this.homePageBean});

  @override
  _VideoCard createState() => _VideoCard();

  @override
  BaseWidgetState getState() {
    return _VideoCard();
  }
}

class _VideoCard extends BaseWidgetState<VideoCard> {
  @override
  Widget build(BuildContext context) {
    return InkWell(
        onTap: () {
          MyNavigator.getInstance().onJumpTo(RouteStatus.detail,
              args: {"videoMo": widget.homePageBean});
        },
        child: SizedBox(
          height: 200,
          child: Card(
            margin: EdgeInsets.only(left: 4, right: 4, bottom: 8),
            //阴影颜色
            color: Colors.white,
            //阴影高度
            elevation: 1.0,
            child: ClipRRect(
              borderRadius: BorderRadius.all(Radius.circular(5)),
              child: Column(
                children: [
                  _itemImage(context),
                  _infoText(),
                ],
              ),
            ),
          ),
        ));
  }

  _itemImage(BuildContext context) {
    final size = MediaQuery.of(context).size;
    return Stack(
      children: [
        cachedImage(
          widget.homePageBean.imageurl,
          height: 120,
          width: size.width / 2 - 20,
        ),
        //left: 0, right: 0, bottom: 0 在下面并且左右填满
        Positioned(
            left: 0,
            right: 0,
            bottom: 0,
            child: Container(
              padding: EdgeInsets.only(left: 8, right: 8, bottom: 3, top: 5),
              //线性渐变
              decoration: BoxDecoration(
                gradient: LinearGradient(
                    begin: Alignment.bottomCenter,
                    end: Alignment.topCenter,
                    colors: [Colors.black54, Colors.transparent]),
              ),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  _iconText(Icons.ondemand_video, widget.homePageBean.playnum),
                  _iconText(Icons.favorite_border, widget.homePageBean.playnum),
                  _iconText(null, widget.homePageBean.videoLength),
                ],
              ),
            ))
      ],
    );
  }

  _iconText(IconData iconData, String playnum) {
    return Row(
      children: [
        if (iconData != null)
          Icon(
            iconData,
            color: Colors.white,
            size: 12,
          ),
        Padding(
          padding: EdgeInsets.only(left: 3, bottom: 3),
          child: Text(
            playnum,
            style: TextStyle(color: Colors.white, fontSize: 10),
          ),
        ),
      ],
    );
  }

  _infoText() {
    return Expanded(
        child: Container(
      padding: EdgeInsets.only(top: 5, left: 8, right: 8, bottom: 5),
      child: Column(
        //从头开始显示
        crossAxisAlignment: CrossAxisAlignment.start,
        //上下显示
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          //文字超多两行省略号
          Text(
            widget.homePageBean.title,
            maxLines: 2,
            overflow: TextOverflow.ellipsis,
            style: TextStyle(fontSize: 12, color: Colors.black87),
          ),
          _owner(),
        ],
      ),
    ));
  }

  _owner() {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      children: [
        Row(
          children: [
            Padding(
              padding: EdgeInsets.only(right: 8),
              child: Text(
                "up",
                style: TextStyle(fontSize: 10, color: Colors.grey),
              ),
            ),
            ClipRRect(
              borderRadius: BorderRadius.circular(12),
              child: Text(
                widget.homePageBean.up,
                style: TextStyle(fontSize: 10, color: Colors.grey),
              ),
            ),
          ],
        ),
        Icon(
          Icons.more_vert_sharp,
          size: 15,
          color: Colors.grey,
        )
      ],
    );
  }
}

视频播放器

这个是在别人基础上改了下,然后直接使用的,具体看一下的的封装使用:

video_card.dart 代码:

import 'dart:async';
import 'dart:math';

import 'package:fijkplayer/fijkplayer.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_blbl/utils/color.dart';
import 'package:flutter_blbl/utils/toast.dart';
import 'package:screen_brightness/screen_brightness.dart';
import 'package:volume_controller/volume_controller.dart';

import 'fijk_controller.dart';

class CustomFijkPanel extends StatefulWidget {
  final FijkPlayer player;
  final BuildContext buildContext;
  final Size viewSize;
  final Rect texturePos;
  final String videoTitle;
  final bool isNextNumber;
  final bool isPlayAd;
  final void Function() onPlayAd;
  final void Function() onBack;
  final void Function() onError;
  final void Function() onVideoEnd;
  final void Function() onVideoPrepared;
  final void Function() onVideoTimeChange;

  /// 播放器控制器具体到源代码目录查看参考fijkplayer\lib\ui\panel.dart
  /// ```
  /// @param {FijkPlayer} player -
  /// @param {BuildContext} buildContext -
  /// @param {Size} viewSize -
  /// @param {Rect} texturePos -
  /// @param {String} videoTitle -
  /// @param {bool} isNextNumber - 全屏后是否显示下一集按钮
  /// @param {bool} isPlayAd - 是否显示广告按钮
  /// @param {void Function()?} onPlayAd - 播放广告
  /// @param {void Function()?} onBack - 返回按钮
  /// @param {void Function()?} onError - 视频错误点击刷新
  /// @param {void Function()?} onVideoEnd - 视频结束
  /// @param {void Function()?} onVideoPrepared - 视频完成后台任务到稳定期
  /// @param {void Function()?} onVideoTimeChange - 视频时间更新
  /// ```
  const CustomFijkPanel({
    @required this.player,
    @required this.buildContext,
    @required this.viewSize,
    @required this.texturePos,
    @required this.videoTitle,
    this.isNextNumber = false,
    this.isPlayAd = false,
    this.onPlayAd,
    this.onBack,
    this.onError,
    this.onVideoEnd,
    this.onVideoPrepared,
    this.onVideoTimeChange,
  });

  @override
  State<StatefulWidget> createState() {
    return _CustomFijkPanelState();
  }
}

class _CustomFijkPanelState extends State<CustomFijkPanel> {
  FijkPlayer get player => widget.player;

  bool get isFullScreen => player.value.fullScreen;

  /// 总时间
  Duration _duration = Duration();

  /// 动画时间
  Duration get _animatedTime => Duration(milliseconds: 400);

  /// 是否在播放
  bool _playing = false;

  /// 后台任务是否初步执行完成是用于正在加载中的状态
  bool _prepared = false;

  /// 视频状态是否执行完成成为稳定状态与_prepared不一致
  bool _playStatePrepared = false;

  bool _isPlayCompleted = false;

  /// 是否在加载中
  bool _buffering = false;
  int _bufferingPro = 0;
  StreamSubscription _bufferingSubs;

  /// 拖动快进的时间 -1不显示
  double _seekPos 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值