flutter进阶之实现一个能够拖动缩放的播放器

    【原创不易,转载请注明出处:https://blog.csdn.net/email_jade/article/details/86715600

    二零一八年的最后一篇博客,写完博客就收拾东西回家了,想想就有点兴奋。

    这次要实现的是一个可以拖动和缩放的播放器,文字总是苍白的,直接看效果吧:

    

    功能分解:

    要实现拖动,那么必须保存播放器的坐标,在拖动的时候不停的更新坐标值即可。

    要实现缩放,那么要保存播放器的长和宽,这里,我遇到的需求是在缩放的时候保持播放器的宽高比不变,因此,还要保存初始的宽高比。

    无论是拖动还是缩放,都有可能出现播放器超出边界的情况,因此,要对边界进行处理。对于左上部分,只要x>=0&&y>=0就是没有超出范围,对于右下部分,只要播放器的w+x <= 边界的w && 播放器的h + y <= 边界的h,那么也是在边界之内。 因此,我们要求取边界的w和h,在flutter求某个控件的宽高用的是:

RenderBox renderObject = _globalKey.currentContext.findRenderObject();

    处理好边界问题,那么就成功了一大半了,对于手势控制的缩放功能,在GestureDetector中直接有对应的Function去监听,对应onScaleStart: onScaleUpdate: onScaleEnd: ,分别代表缩放开始,缩放中,缩放结束。三个函数的参数值ScaleStartDetails、ScaleUpdateDetails、ScaleEndDetails中都有我们缩放的比例,以及缩放中心的坐标。对于拖动,直接使用ScaleUPdateDetails的左边进行计算即可。

    视频播放器,选择的是官方的播放器video_player,视频播放部分比较简单,直接参考官方的example就可以了。当然如果要支持rtsp请看我的另一篇博客:https://blog.csdn.net/email_jade/article/details/86650561

  好了,到目前为止感觉没有太多要注意的地方,不过考虑到这部分相对于其他使用频率低,还是放在进阶部分。

  贴上一些关键部分的代码:

    边界背景:

import 'package:flutter/material.dart';
import 'package:flutter_view/widget/video_view.dart';

class Background extends StatefulWidget{
  @override
  State<StatefulWidget> createState() {
    return BackgroundState();
  }

}

class BackgroundState extends State<Background>{
  static const double DEFAULT_WIDTH = 160;
  static const double DEFAULT_HEIGHT = 90;
  GlobalKey _globalKey = new GlobalKey();
  //视频的参数,宽,高,比例
  double _width;
  double _height;
  double _x;
  double _y;
  double _ratio;

  //临时变量
  double _tmpW;
  double _tmpH;
  Offset _lastOffset;

  //背景的宽高
  double _bgW;
  double _bgH;

  @override
  void initState() {
    super.initState();
    //一些参数的初始化
    _width = DEFAULT_WIDTH;
    _height = DEFAULT_HEIGHT;
    _x = _width;
    _y = _height;
    _ratio = _width / _height;
    _tmpW = _width;
    _tmpH = _height;
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: <Widget>[
        Container(key:_globalKey, color: Colors.blueGrey, width: double.infinity, height: double.infinity,),
        Positioned(child: GestureDetector(child:CustomView(width: _width, height: _height, url: "http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4",), onScaleEnd: scaleEnd, onScaleStart: scaleStart, onScaleUpdate: scaleUpdate,), left: _x, top: _y,),
      ],
    );
  }

  //计算背景的宽高
  void getBgInfo(){
    RenderBox renderObject = _globalKey.currentContext.findRenderObject();
    _bgW = renderObject.paintBounds.size.width;
    _bgH = renderObject.paintBounds.size.height;
  }

  //开始缩放
  void scaleStart(ScaleStartDetails details){
    _tmpW = _width;
    _tmpH = _height;
    _lastOffset = details.focalPoint;
    getBgInfo();
  }

  //缩放更新
  void scaleUpdate(ScaleUpdateDetails details){

    setState(() {
      _width = _tmpW*details.scale;
      _height = _tmpH*details.scale;
      _x += (details.focalPoint.dx - _lastOffset.dx) ;
      _y += (details.focalPoint.dy - _lastOffset.dy);
      //边界判定,保持宽高比
      if(_width > _bgW){
        _width = _bgW;
        _height = _width / _ratio;
      }
      if(_height > _bgH){
        _height = _bgH;
        _width = _height * _ratio;
      }
      if(_x < 0){
        _x = 0;
      }
      if(_y < 0){
        _y = 0;
      }
      if(_x > _bgW-_width){
        _x = _bgW-_width;
      }
      if(_y > _bgH-_height){
        _y = _bgH-_height;
      }
      _lastOffset = details.focalPoint;
    });
  }

  //缩放结束
  void scaleEnd(ScaleEndDetails details){
    _tmpW = _width;
    _tmpH = _height;
    //边界判定,保持宽高比
    if(_width < DEFAULT_WIDTH){
      _width = DEFAULT_WIDTH;
      _height = _width / _ratio;
    }
    if(_height < DEFAULT_HEIGHT){
      _height = DEFAULT_HEIGHT;
      _width = _height * _ratio;
    }
  }

}

    播放器:

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

class CustomView extends StatefulWidget{
  final double width;
  final double height;
  final String url;

  const CustomView({@required this.width, @required this.height, @required this.url});

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

}

class CustomViewState extends State<CustomView>{
  VideoPlayerController _controller;
  @override
  void initState() {
    super.initState();
    _controller = VideoPlayerController.network(
        widget.url)
      ..initialize().then((_) {
        setState(() {});
        _controller.setLooping(true);
        _controller.play();
      });
  }
  @override
  Widget build(BuildContext context) {
    return Container(
      width: widget.width,
      height: widget.height,
      child: _controller.value.initialized ? VideoPlayer(_controller) : Container(color: Colors.black,),
    );
  }

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

  完整代码见:

    https://github.com/jadennn/flutter_view

 

   flutter很好,路还很长,让我们一起奋斗前行!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值