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);
_initializeVideoPlayerFuture = _controller.initialize().then((_) {
if (_controller.value.size.width < _controller.value.size.height) {
//宽度小于高度: 竖屏视频
_sizeWidth = 9.0;
_sizeHeight = 16.0;
}else{
//宽度大于高度: 横屏视频
_sizeWidth = 16.0;
_sizeHeight = 9.0;
}
_controller.setLooping(true);
});
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(),
);
},
);
}
}