浏览代码

增加了进度条的手势

Caijinglong 6 年之前
父节点
当前提交
207f6cecfd

+ 22 - 3
TODOLIST.md

@@ -1,22 +1,41 @@
 # TodoList
 
 - [x] 控制器逻辑
+  - [x] 设置数据源
+    - [x] 网络
+    - [x] 本地
+    - [x] 资产
+  - [x] 播放
+  - [x] 暂停
+  - [x] 停止
+  - [x] 释放资源
+  - [x] 控制音量
+  - [x] 控制系统音量
+  - [x] 获取视频信息
+    - [x] 宽高
+    - [x] 当前播放进度
+    - [x] 总时长
+    - [x] 视频方向
+  - [ ] 控制亮度
 - [x] 默认控制器 UI
   - [x] 进度条
   - [x] 播放/暂停按钮
-  - [x] 横向滑动进度
+  - [x] 全屏横向滑动进度
+  - [ ] 拖动进度条快速调节进度
+    - [x] 逻辑部分实现
+    - [ ] UI 提示
   - [x] 纵向滑动音量
   - [x] 单击显示/隐藏界面
   - [x] 双击播放/暂停
-  - [ ] 拖动进度条快速调节进度
   - [x] 使用选项切换音量的控制是系统音量还是资源音量
   - [x] 允许根据情况禁用各种控制手势
+  - [ ] 当一个视频是直播视频时,进度条应该隐藏,且无拖动进度相关手势
 - [x] 根据视频角度自动旋转
 - [x] 保证图片宽高比不失真
 - [x] 允许自定义控制器 UI
 - [ ] 完善示例代码
   - [x] 播放网络
   - [x] 播放相册
-  - [ ] 播放 asset
+  - [x] 播放 asset
   - [ ] 设置选项的使用
   - [ ] 全屏播放的示例代码

+ 37 - 0
example/lib/page/asset_page.dart

@@ -0,0 +1,37 @@
+import 'package:flutter/material.dart';
+import 'package:flutter_ijkplayer/flutter_ijkplayer.dart';
+
+class AssetPage extends StatefulWidget {
+  @override
+  _AssetPageState createState() => _AssetPageState();
+}
+
+class _AssetPageState extends State<AssetPage> {
+  IjkMediaController controller = IjkMediaController();
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: AppBar(
+        title: Text("播放资产"),
+      ),
+      body: ListView(
+        children: <Widget>[
+          AspectRatio(
+            aspectRatio: 1,
+            child: IjkPlayer(
+              mediaController: controller,
+            ),
+          )
+        ],
+      ),
+      floatingActionButton: FloatingActionButton(
+        child: Icon(Icons.play_arrow),
+        onPressed: () async {
+          await controller.setAssetDataSource("assets/sample1.mp4");
+          await controller.play();
+        },
+      ),
+    );
+  }
+}

+ 4 - 1
example/lib/page/gallery_page.dart

@@ -77,6 +77,9 @@ class _PlayGalleryPageState extends State<PlayGalleryPage> {
 
   void _playVideo() async {
     if (this.file != null && this.file.existsSync())
-      await mediaController.setFileDataSource(file, autoPlay: true);
+      await mediaController.setFileDataSource(
+        file,
+        autoPlay: true,
+      );
   }
 }

+ 2 - 0
example/lib/page/index.dart

@@ -1,4 +1,5 @@
 import 'package:flutter/material.dart';
+import 'package:ijkplayer_example/page/asset_page.dart';
 import 'package:ijkplayer_example/page/gallery_page.dart';
 import 'package:ijkplayer_example/page/network.dart';
 
@@ -18,6 +19,7 @@ class _IndexPageState extends State<IndexPage> {
         children: <Widget>[
           buildButton("播放网络视频", NetworkPage()),
           buildButton("播放相册视频", PlayGalleryPage()),
+          buildButton("播放应用asset", AssetPage()),
         ],
       ),
     );

+ 1 - 1
example/lib/page/network.dart

@@ -14,7 +14,7 @@ class _NetworkPageState extends State<NetworkPage> {
   void initState() {
     super.initState();
     editingController.text =
-        "https://www.sample-videos.com/video123/mp4/720/big_buck_bunny_720p_20mb.mp4";
+        "https://www.sample-videos.com/video123/mp4/720/big_buck_bunny_720p_30mb.mp4";
   }
 
   @override

+ 7 - 0
lib/src/controller.dart

@@ -203,6 +203,13 @@ class IjkMediaController {
     refreshVideoInfo();
   }
 
+  Future<void> seekToProgress(double progress) async {
+    var videoInfo = await getVideoInfo();
+    var target = videoInfo.duration * progress;
+    await this.seekTo(target);
+    refreshVideoInfo();
+  }
+
   /// get video info from native
   Future<VideoInfo> getVideoInfo() async {
     Map<String, dynamic> result = await _plugin?.getInfo();

+ 28 - 0
lib/src/helper/ui_helper.dart

@@ -0,0 +1,28 @@
+import 'package:flutter/widgets.dart';
+
+class UIHelper {
+  static Rect findGlobalRect(GlobalKey key) {
+    RenderBox renderObject = key.currentContext?.findRenderObject();
+    if (renderObject == null) {
+      return null;
+    }
+
+    var globalOffset = renderObject?.localToGlobal(Offset.zero);
+
+    if (globalOffset == null) {
+      return null;
+    }
+
+    var bounds = renderObject.paintBounds;
+    bounds = bounds.translate(globalOffset.dx, globalOffset.dy);
+    return bounds;
+  }
+
+  static Offset globalOffsetToLocal(GlobalKey key, Offset offsetGlobal) {
+    RenderBox renderObject = key.currentContext?.findRenderObject();
+    if (renderObject == null) {
+      return null;
+    }
+    return renderObject.globalToLocal(offsetGlobal);
+  }
+}

+ 8 - 1
lib/src/widget/controller_widget_builder.dart

@@ -430,11 +430,18 @@ class PortraitController extends StatelessWidget {
   }
 
   Widget buildProgress(VideoInfo info) {
+    if (info.duration == 0) {
+      return Container();
+    }
     return Container(
-      height: 5,
+      height: 22,
       child: ProgressBar(
         current: info.currentPosition,
         max: info.duration,
+        changeProgressHandler: (progress) async {
+          await controller.seekToProgress(progress);
+        },
+        tapProgressHandler: (progress) {},
       ),
     );
   }

+ 92 - 9
lib/src/widget/progress_bar.dart

@@ -1,12 +1,20 @@
 import 'package:flutter/material.dart';
+import 'package:flutter_ijkplayer/src/helper/ui_helper.dart';
 
-class ProgressBar extends StatelessWidget {
+typedef ChangeProgressHandler(double progress);
+
+typedef TapProgressHandler(double progress);
+
+class ProgressBar extends StatefulWidget {
   final double max;
   final double current;
   final double buffered;
   final Color backgroundColor;
   final Color bufferColor;
   final Color playedColor;
+  final ChangeProgressHandler changeProgressHandler;
+  final TapProgressHandler tapProgressHandler;
+  final double progressFlex;
 
   const ProgressBar({
     Key key,
@@ -16,21 +24,45 @@ class ProgressBar extends StatelessWidget {
     this.backgroundColor = const Color(0xFF616161),
     this.bufferColor = Colors.grey,
     this.playedColor = Colors.white,
+    this.changeProgressHandler,
+    this.tapProgressHandler,
+    this.progressFlex = 0.6,
   }) : super(key: key);
 
+  @override
+  _ProgressBarState createState() => _ProgressBarState();
+}
+
+class _ProgressBarState extends State<ProgressBar> {
+  GlobalKey _progressKey = GlobalKey();
+
   @override
   Widget build(BuildContext context) {
-    if (max == null || current == null || max == 0) return _buildEmpty();
+    if (widget.max == null || widget.current == null || widget.max == 0)
+      return _buildEmpty();
 
-    var left = current / max;
-    var mid = (buffered ?? 0) / max - left;
+    var left = widget.current / widget.max;
+    var mid = (widget.buffered ?? 0) / widget.max - left;
     if (mid < 0) {
       mid = 0;
     }
 
     var right = 1 - left - mid;
 
-    var progress = buildProgress(left, mid, right);
+    Widget progress = buildProgress(left, mid, right);
+
+    if (widget.changeProgressHandler != null &&
+        widget.tapProgressHandler != null) {
+      progress = GestureDetector(
+        child: progress,
+        behavior: HitTestBehavior.translucent,
+        onPanUpdate: _onPanUpdate,
+        onHorizontalDragUpdate: _onHorizontalDragUpdate,
+        onTapDown: _onTapDown,
+        onTapUp: _onTapUp,
+      );
+    }
+
     return progress;
   }
 
@@ -38,12 +70,24 @@ class ProgressBar extends StatelessWidget {
     return Container();
   }
 
+  int get flex => (widget.progressFlex * 100).toInt();
+
   Widget buildProgress(double left, double mid, double right) {
-    return Row(
+    return Column(
       children: <Widget>[
-        buildColorWidget(playedColor, left),
-        buildColorWidget(bufferColor, mid),
-        buildColorWidget(backgroundColor, right),
+        Flexible(child: Container(), flex: 100 - flex ~/ 2),
+        Flexible(
+          flex: flex,
+          child: Row(
+            key: _progressKey,
+            children: <Widget>[
+              buildColorWidget(widget.playedColor, left),
+              buildColorWidget(widget.bufferColor, mid),
+              buildColorWidget(widget.backgroundColor, right),
+            ],
+          ),
+        ),
+        Flexible(child: Container(), flex: 100 - flex ~/ 2),
       ],
     );
   }
@@ -64,4 +108,43 @@ class ProgressBar extends StatelessWidget {
       ),
     );
   }
+
+  void _onTapDown(TapDownDetails details) {
+    var progress = getProgress(details.globalPosition);
+    widget.tapProgressHandler(progress);
+  }
+
+  void _onPanUpdate(DragUpdateDetails details) {
+    var progress = getProgress(details.globalPosition);
+    widget.tapProgressHandler(progress);
+  }
+
+  void _onTapUp(TapUpDetails details) {
+    var progress = getProgress(details.globalPosition);
+    widget.changeProgressHandler(progress);
+  }
+
+  void _onHorizontalDragUpdate(DragUpdateDetails details) {
+    var progress = getProgress(details.globalPosition);
+    widget.tapProgressHandler(progress);
+  }
+
+  double getProgress(Offset globalPosition) {
+    var offset = _getLocalOffset(globalPosition);
+    var globalRect = UIHelper.findGlobalRect(_progressKey);
+    var progress = offset.dx / globalRect.width;
+    if (progress > 1) {
+      progress = 1;
+    } else if (progress < 0) {
+      progress = 0;
+    }
+    return progress;
+  }
+
+  Offset _getLocalOffset(Offset globalPosition) {
+    return UIHelper.globalOffsetToLocal(
+      _progressKey,
+      globalPosition,
+    );
+  }
 }