Browse Source

Merge pull request #17 from CaiJingLong/dev

Overlay example and full screen
Caijinglong 6 years ago
parent
commit
ca80373180

+ 8 - 2
TODOLIST.md

@@ -37,6 +37,9 @@
   - [x] 屏幕旋转: 这个指强制当前屏幕旋转至哪个方向
     - [ ] iPad 无效,暂不知原因
   - [x] 截图
+  - [ ]  悬浮窗中播放
+    - [ ] 悬浮窗的UI控制器
+    - [ ] 自定义UI
 - [x] 默认控制器 UI
   - [x] 进度条
   - [x] 播放/暂停按钮
@@ -57,7 +60,7 @@
     - [x] 利用 ShowDialog 开发一个全屏的播放界面,不仅仅在 Example 中
       - [x] 根据屏幕宽高确定是横屏全屏还是竖屏全屏(比如:常规电影是横屏,常规自拍类视频为竖屏)
 - [x] 根据视频角度自动旋转
-- [x] 保证图片宽高比不失真
+- [x] 保证视频图像宽高比不失真
 - [x] 允许自定义控制器 UI
 - [ ] 未开始播放时的界面
   - [ ] 默认
@@ -69,5 +72,8 @@
   - [ ] 设置选项的使用
   - [x] 切换全屏播放的示例代码
   - [x] 在列表中(ListView)
-  - [ ] 视频竖向分页滑动
+  - [x] 视频竖向分页滑动
+  - [x] 在悬浮窗中播放
+    - [x] 悬浮窗的UI控制器
+      - [ ] 允许自定义UI
 - [x] iOS 部分视频无法显示图像的问题: 可能很长时间内都无法解决

+ 3 - 0
example/lib/i18n/cn.dart

@@ -59,4 +59,7 @@ class _I18nZh extends I18n {
 
   @override
   String get screenshotTitle => "截取视频画面(开发中)";
+
+  @override
+  String get overlayPageTitle => "悬浮窗中显示";
 }

+ 3 - 0
example/lib/i18n/en.dart

@@ -58,4 +58,7 @@ class _I18nEn extends I18n {
 
   @override
   String get screenshotTitle => "screenshot video frame(experiment)";
+
+  @override
+  String get overlayPageTitle => "In overlay";
 }

+ 2 - 0
example/lib/i18n/i18n.dart

@@ -42,6 +42,8 @@ abstract class I18n {
   String get playFinishToast;
 
   String get screenshotTitle;
+
+  String get overlayPageTitle;
 }
 
 I18n get currentI18n => I18n(window.locale);

+ 239 - 0
example/lib/page/in_overlay_page.dart

@@ -0,0 +1,239 @@
+import 'dart:ui' as ui;
+
+import 'package:flutter/material.dart';
+import 'package:flutter_ijkplayer/flutter_ijkplayer.dart';
+import 'package:ijkplayer_example/i18n/i18n.dart';
+
+class InOverlayPage extends StatefulWidget {
+  @override
+  _InOverlayPageState createState() => _InOverlayPageState();
+}
+
+class _InOverlayPageState extends State<InOverlayPage> {
+  IjkMediaController controller = IjkMediaController();
+  OverlayEntry entry;
+
+  @override
+  void initState() {
+    super.initState();
+    controller.setDataSource(
+      DataSource.network(
+        "http://img.ksbbs.com/asset/Mon_1703/05cacb4e02f9d9e.mp4",
+      ),
+      autoPlay: true,
+    );
+  }
+
+  @override
+  void deactivate() {
+    super.deactivate();
+    entry?.remove();
+    entry = null;
+  }
+
+  @override
+  void dispose() {
+    controller?.dispose();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Scaffold(
+      appBar: AppBar(
+        title: Text(currentI18n.overlayPageTitle),
+      ),
+      body: ListView(
+        children: <Widget>[
+          AspectRatio(
+            child: IjkPlayer(
+              mediaController: controller,
+            ),
+            aspectRatio: 1,
+          ),
+          FlatButton(
+            child: Text("showInOverlay"),
+            onPressed: showInOverlay,
+          ),
+        ],
+      ),
+    );
+  }
+
+  void showInOverlay() async {
+    var info = await controller.getVideoInfo();
+    OverlayEntry _entry;
+    _entry = OverlayEntry(
+      builder: (BuildContext context) {
+        return OverlayWidget(
+          controller: controller,
+          initVideoInfo: info,
+          onTapClose: () {
+            _entry?.remove();
+          },
+        );
+      },
+    );
+    Overlay.of(context).insert(_entry);
+  }
+}
+
+class OverlayWidget extends StatefulWidget {
+  final VideoInfo initVideoInfo;
+  final IjkMediaController controller;
+  final Function onTapClose;
+
+  const OverlayWidget({
+    Key key,
+    this.initVideoInfo,
+    this.controller,
+    this.onTapClose,
+  }) : super(key: key);
+
+  @override
+  _OverlayWidgetState createState() => _OverlayWidgetState();
+}
+
+const double _overlayWidth = 100;
+
+class _OverlayWidgetState extends State<OverlayWidget> {
+  double dx = 0;
+  double dy = 1;
+
+  @override
+  Widget build(BuildContext context) {
+    return NotificationListener<OffsetNotication>(
+      onNotification: _onOffsetNoticiation,
+      child: Align(
+        alignment: Alignment(dx, dy),
+        child: Container(
+          width: _overlayWidth,
+          child: AspectRatio(
+            aspectRatio: widget.initVideoInfo.ratio,
+            child: IjkPlayer(
+              mediaController: widget.controller,
+              controllerWidgetBuilder: (ctl) {
+                return OverlayControllerWidget(
+                  controller: ctl,
+                  onTapClose: widget.onTapClose,
+                );
+              },
+            ),
+          ),
+        ),
+      ),
+    );
+  }
+
+  Offset _startOffset;
+
+  bool _onOffsetNoticiation(OffsetNotication notification) {
+    if (notification.type == OffsetType.start) {
+      _startOffset = Offset(dx, dy);
+      return true;
+    }
+
+    var offset = notification.offset;
+
+    var size = MediaQuery.of(context).size;
+
+    dx = _startOffset.dx + offset.dx / size.width * 2;
+    dy = _startOffset.dy + offset.dy / size.height * 2;
+
+    print("dx = $dx");
+    print("dy = $dy");
+
+    if (dx > 1) {
+      dx = 1;
+    } else if (dx < -1) {
+      dx = -1;
+    }
+
+    if (dy > 1) {
+      dy = 1;
+    } else if (dy < -1) {
+      dy = -1;
+    }
+
+    setState(() {});
+    return true;
+  }
+}
+
+class OverlayControllerWidget extends StatefulWidget {
+  final IjkMediaController controller;
+  final Function onTapClose;
+
+  const OverlayControllerWidget({
+    Key key,
+    this.controller,
+    this.onTapClose,
+  }) : super(key: key);
+
+  @override
+  _OverlayControllerWidgetState createState() =>
+      _OverlayControllerWidgetState();
+}
+
+class _OverlayControllerWidgetState extends State<OverlayControllerWidget> {
+  bool showController = false;
+
+  @override
+  Widget build(BuildContext context) {
+    Widget child;
+    if (!showController) {
+      child = Container();
+    } else {
+      child = Container(
+        color: Colors.black.withOpacity(0.6),
+        child: Align(
+          alignment: Alignment.topRight,
+          child: Container(
+            child: IconButton(
+              color: Colors.white,
+              icon: Icon(Icons.close),
+              onPressed: widget.onTapClose,
+            ),
+          ),
+        ),
+      );
+    }
+    return GestureDetector(
+      child: child,
+      behavior: HitTestBehavior.opaque,
+      onTap: () => setState(() => showController = !showController),
+      // onPanUpdate: (detail) {
+      //   var notification = OffsetNotication()
+      //     ..offset = detail.delta
+      //     ..type = OffsetType.update;
+      //   notification.dispatch(context);
+      // },
+
+      // onPanStart: (detail) {
+      //   var notication = OffsetNotication()..type = OffsetType.start;
+      //   notication.dispatch(context);
+      // },
+      onLongPressMoveUpdate: (detail) {
+        var notification = OffsetNotication()
+          ..offset = detail.offsetFromOrigin
+          ..type = OffsetType.update;
+        notification.dispatch(context);
+      },
+      onLongPressStart: (detail) {
+        var n = OffsetNotication()..type = OffsetType.start;
+        n.dispatch(context);
+      },
+    );
+  }
+}
+
+class OffsetNotication extends Notification {
+  Offset offset;
+
+  OffsetType type;
+}
+
+enum OffsetType {
+  start,
+  update,
+}

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

@@ -5,6 +5,7 @@ import 'package:ijkplayer_example/page/controller_stream_use.dart';
 import 'package:ijkplayer_example/page/dialog_video_page.dart';
 import 'package:ijkplayer_example/page/full_screen.dart';
 import 'package:ijkplayer_example/page/gallery_page.dart';
+import 'package:ijkplayer_example/page/in_overlay_page.dart';
 import 'package:ijkplayer_example/page/network.dart';
 import 'package:ijkplayer_example/page/paging_page.dart';
 import 'package:ijkplayer_example/page/screen_shot_page.dart';
@@ -34,6 +35,7 @@ class _IndexPageState extends State<IndexPage> {
           buildButton(currentI18n.pageViewButton, PagingPickPage()),
           buildButton(currentI18n.useStreamUsage, ControllerStreamUsagePage()),
           buildButton(currentI18n.screenshotTitle, ScreenShotPage()),
+          buildButton(currentI18n.overlayPageTitle, InOverlayPage()),
         ],
       ),
     );

+ 2 - 2
lib/src/engine/manager.dart

@@ -55,13 +55,13 @@ class IjkManager {
 
   static setLandScape() async {
     if (Platform.isAndroid) {
-      SystemChrome.setPreferredOrientations(
+      await SystemChrome.setEnabledSystemUIOverlays([]);
+      await SystemChrome.setPreferredOrientations(
         [
           DeviceOrientation.landscapeLeft,
           DeviceOrientation.landscapeRight,
         ],
       );
-      SystemChrome.setEnabledSystemUIOverlays([]);
     } else if (Platform.isIOS) {
       await setSupportOrientation([
         DeviceOrientation.landscapeLeft,

+ 11 - 5
lib/src/widget/controller_widget_builder.dart

@@ -4,8 +4,8 @@ import 'package:flutter/cupertino.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter_ijkplayer/flutter_ijkplayer.dart';
-import 'package:flutter_ijkplayer/src/helper/time_helper.dart';
 import 'package:flutter_ijkplayer/src/helper/logutil.dart';
+import 'package:flutter_ijkplayer/src/helper/time_helper.dart';
 import 'package:flutter_ijkplayer/src/helper/ui_helper.dart';
 import 'package:flutter_ijkplayer/src/widget/progress_bar.dart';
 
@@ -619,17 +619,23 @@ enum VolumeType {
 
 showFullScreenIJKPlayer(
     BuildContext context, IjkMediaController controller) async {
-  showDialog(
-    context: context,
-    builder: (ctx) => IjkPlayer(
+  Navigator.push(
+    context,
+    MaterialPageRoute(
+      builder: (c) {
+        return IjkPlayer(
           mediaController: controller,
           controllerWidgetBuilder: (ctl) =>
               _buildFullScreenMediaController(ctl, true),
-        ),
+        );
+      },
+      fullscreenDialog: true,
+    ),
   ).then((_) {
     IjkManager.unlockOrientation();
     IjkManager.setCurrentOrientation(DeviceOrientation.portraitUp);
   });
+
   var info = await controller.getVideoInfo();
 
   Axis axis;