二零一八年的最後一篇博客,寫完博客就收拾東西回家了,想想就有點興奮。
這次要實現的是一個可以拖動和縮放的播放器,文字總是蒼白的,直接看效果吧:
功能分解:
要實現拖動,那麼必須保存播放器的座標,在拖動的時候不停的更新座標值即可。
要實現縮放,那麼要保存播放器的長和寬,這裏,我遇到的需求是在縮放的時候保持播放器的寬高比不變,因此,還要保存初始的寬高比。
無論是拖動還是縮放,都有可能出現播放器超出邊界的情況,因此,要對邊界進行處理。對於左上部分,只要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很好,路還很長,讓我們一起奮鬥前行!