flutter VideoPlayer适配:保持视频的原始宽高比,缩放视频使它完全覆盖父容器

在这里插入图片描述
需求:视频充满整个长方形容器不能有黑边;视频不能拉伸变形;视频可以显示不全。

当播放器放置在列表中时,它固定了宽度及高度是一个width : height 为16:9的横向长方形。
情况1:不使用AspectRatio设置横纵比例,它会默认充满整个父容器,用户上传横屏视频比例相差不大显示较为正常,当用户上传竖屏视频时会横向拉伸显示变形。
情况2:使用AspectRatio设置横纵比例,当用户上传竖屏视频时会在中间显示,左右两边出现大片空白区域。

适配:使用FittedBox设置BoxFit.cover使子控件等比占据父容器,再使用SizedBox.expand尽量大的填充父布局,最后ClipRRect裁剪掉超出Container容器的部分。此时

视频播放器适配代码:

import 'package:atui/jade/configs/PathConfig.dart';
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';

class TestVideo extends StatefulWidget{
  
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return _TestVideo();
  }
}

class _TestVideo extends State<TestVideo>{

  VideoPlayerController _controller;
  Future<void> _initializeVideoPlayerFuture;
  double aspectRadio = 16.0 / 9.0;

  double _sizeWidth = 0.0;
  double _sizeHeight = 0.0;

  
  void initState() {
    // TODO: implement initState
    super.initState();
    _controller = VideoPlayerController.network(
      //竖屏测试视频
    //  'https://zmkx.oss-cn-hangzhou.aliyuncs.com/oss/folder/atui2024-10-281730076387146f6b3a41047074243b8624b9994eff6a1zjuqd6qtbonq.mp4',
      //横屏测试视频
      'https://media.w3.org/2010/05/sintel/trailer.mp4',
    );
    _controller.setVolume(0);
    _controller.setLooping(true);
    _initializeVideoPlayerFuture = _controller.initialize().then((_) {
//============================方式1===================================
	  //由于不是精确的宽高,这种方式有缺陷仍然对于一些视频仍有拉伸(适用于有特殊需求的设计在这基础上改动)
      if (_controller.value.size.width < _controller.value.size.height) {
        //宽度小于高度: 竖屏视频
        _sizeWidth = 9.0;
        _sizeHeight = 16.0;
      }else{
        //宽度大于高度: 横屏视频
        _sizeWidth = 16.0;
        _sizeHeight = 9.0;
      }

//=========================方式2===============================
// 获取视频宽度和高度在配置给SizeBox,这样所有尺寸的视频都不会有变形
_sizeWidth  = _controller.value.size?.width;
_sizeHeight = _controller.value.size?.height;

      
    });

    print('比例 ${_controller.value.aspectRatio}');
  }


  
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      body: _body(),
    );
  }

  _body(){
    return Center(
      child: Column(
        children: [
          SizedBox(height: 300,),
          ClipRRect( //裁剪掉超出Container容器的部分
              borderRadius: BorderRadius.circular(5),
              child: Container(
                  width: 320,height: 180,
                  color: Colors.green,
                  alignment: Alignment.center,
                  child: _video()
              ))
        ],
      )
    );
  }


  _video(){
    return FutureBuilder(
      future: _initializeVideoPlayerFuture,
      builder: (context, snapshot) {
        return snapshot.connectionState == ConnectionState.done
            ? Stack(
          children: [
            SizedBox.expand(//尽量大的去填充父布局
                child: FittedBox(//使用FittedBox设置BoxFit.cover使子控件等比占据父容器
                  fit: BoxFit.cover,
                  child: SizedBox(
                      width: _sizeWidth,height: _sizeHeight,
                      child: VideoPlayer(_controller)),
                )
            ),

            GestureDetector(
              onTap: (){
                if(_controller.value.isPlaying){
                  _controller.pause();
                }else {
                  _controller.play();
                }
              },
              child:  Center(
                child: Offstage(
                  offstage: _controller.value.isPlaying,
                  child: Image.asset(PathConfig.iconPause,
                    width: 40,
                    height: 40,
                  ),
                ),
              )
            ),
          ],
        )
            : Center(
          child: CircularProgressIndicator(),
        );
      },
    );
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值