瀏覽代碼

添加横向滑动改变进度,左右上滑调节亮度音量功能

hwh97 6 年之前
父節點
當前提交
ad62055aa8
共有 4 個文件被更改,包括 247 次插入10 次删除
  1. 3 5
      example/lib/main.dart
  2. 233 3
      lib/src/i2_material_controls.dart
  3. 6 2
      lib/src/material_progress_bar.dart
  4. 5 0
      pubspec.yaml

+ 3 - 5
example/lib/main.dart

@@ -33,7 +33,7 @@ class _ChewieDemoState extends State<ChewieDemo> {
   void initState() {
     super.initState();
     _videoPlayerController1 = VideoPlayerController.network(
-        'https://v-cdn.zjol.com.cn/276998.mp4')
+        'http://mirror.aarnet.edu.au/pub/TED-talks/911Mothers_2010W-480p.mp4')
       ..initialize().then((_){
         _chewieController = ChewieController(
           videoPlayerController: _videoPlayerController1,
@@ -41,9 +41,7 @@ class _ChewieDemoState extends State<ChewieDemo> {
           aspectRatio: _videoPlayerController1.value.aspectRatio,
           autoPlay: true,
           looping: true,
-          customControls: I2MaterialControls(
-
-          ),
+          customControls: I2MaterialControls(),
         );
         setState(() {
         });
@@ -80,7 +78,7 @@ class _ChewieDemoState extends State<ChewieDemo> {
             Stack(
               children: <Widget>[
                 Container(
-                  constraints: BoxConstraints(maxHeight: 200),
+//                  constraints: BoxConstraints(maxHeight: 200),
                   child: _chewieController == null ? Container() : Chewie(
                     controller: _chewieController,
                   ),

+ 233 - 3
lib/src/i2_material_controls.dart

@@ -6,6 +6,8 @@ import 'package:chewie/src/material_progress_bar.dart';
 import 'package:chewie/src/utils.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
+import 'package:screen/screen.dart';
+import 'package:sys_volume/flutter_volume.dart';
 import 'package:video_player/video_player.dart';
 
 class I2MaterialControls extends StatefulWidget {
@@ -18,6 +20,11 @@ class I2MaterialControls extends StatefulWidget {
   }
 }
 
+enum VerticalMode {
+  Volume,
+  Bright
+}
+
 class _MaterialControlsState extends State<I2MaterialControls> {
   VideoPlayerValue _latestValue;
   double _latestVolume;
@@ -34,6 +41,20 @@ class _MaterialControlsState extends State<I2MaterialControls> {
   VideoPlayerController controller;
   ChewieController chewieController;
 
+  /// 横向视频进度拖动 BiLiBiLi的逻辑 duration > 90 ? 90s : duration * 0.8
+  double startDx;
+  double lastDx;
+  Duration dragDuration;
+  Duration updateDragDuration;
+  /// 竖向音量亮度拖动 100%调整的逻辑
+  double startDy;
+  double endDy;
+  VerticalMode _verticalMode;
+  double savedBright;
+  double currentBright;
+  double currentVolume;
+  String valueText;
+
   @override
   Widget build(BuildContext context) {
     if (_latestValue.hasError) {
@@ -57,6 +78,124 @@ class _MaterialControlsState extends State<I2MaterialControls> {
       },
       child: GestureDetector(
         onTap: () => _cancelAndRestartTimer(),
+        onVerticalDragStart: (DragStartDetails details) async {
+          print("onVerticalDragStart ${details.globalPosition}");
+          // 判断距离 只响应2/5的左边和2/5的右边
+          if (details.globalPosition.dx < MediaQuery.of(context).size.width / 5 * 2) {
+            // 响应亮度
+            startDy = details.globalPosition.dy;
+            _verticalMode = VerticalMode.Bright;
+            currentBright = await Screen.brightness;
+          } else if (details.globalPosition.dx > MediaQuery.of(context).size.width / 5 * 3) {
+            // 响应音量
+            startDy = details.globalPosition.dy;
+            _verticalMode = VerticalMode.Volume;
+            currentVolume = await FlutterVolume.get();
+          } else {
+            // 中间位置不响应 reset
+            setState(() {
+              _verticalMode = null;
+              currentBright = null;
+              currentVolume = null;
+              startDy = null;
+              endDy = null;
+            });
+          }
+        },
+        onVerticalDragUpdate: (DragUpdateDetails details) async {
+          print("onVerticalDragUpdate ${details.globalPosition}");
+          if (_verticalMode != null) {
+            // 显示数值(百分比)
+            setState(() {
+              endDy = details.globalPosition.dy;
+            });
+            if (_verticalMode != null && endDy != null && startDy != null) {
+              double value;
+              if (_verticalMode == VerticalMode.Bright) {
+                if (endDy > startDy) {
+                  // 降低操作 竖屏环境?????
+                  value = (currentBright - (endDy - startDy) / MediaQuery.of(context).size.height) < 0
+                      ? 0
+                      : (currentBright - (endDy - startDy) / MediaQuery.of(context).size.height);
+                } else {
+                  // 拉高操作 竖屏环境?????
+                  value = (currentBright + (startDy - endDy) / MediaQuery.of(context).size.height) >= 1
+                      ? 1
+                      : (currentBright + (startDy - endDy) / MediaQuery.of(context).size.height);
+                }
+                Screen.setBrightness(value);
+              } else {
+                if (endDy > startDy) {
+                  // 降低操作 竖屏环境?????
+                  value = (currentVolume - (endDy - startDy) / MediaQuery.of(context).size.height) < 0
+                      ? 0
+                      : (currentVolume - (endDy - startDy) / MediaQuery.of(context).size.height);
+                } else {
+                  // 拉高操作 竖屏环境?????
+                  value = (currentVolume + (startDy - endDy) / MediaQuery.of(context).size.height) >= 1
+                      ? 1
+                      : (currentVolume + (startDy - endDy) / MediaQuery.of(context).size.height);
+                }
+                FlutterVolume.set(value);
+              }
+              if (value == 1 || value == 0) {
+                // reset dy
+                startDy = endDy;
+                currentBright = await Screen.brightness;
+                currentVolume = await FlutterVolume.get();
+              }
+              setState(() {
+                valueText = (value * 100).toStringAsFixed(0);
+              });
+            }
+
+          }
+        },
+        onVerticalDragEnd: (DragEndDetails details){
+          setState(() {
+            _verticalMode = null;
+            currentBright = null;
+            startDy = null;
+            endDy = null;
+          });
+        },
+        onHorizontalDragStart: (DragStartDetails detail) {
+          if (_latestValue.duration == null) return;
+          _cancelAndRestartTimer();
+          startDx = detail.localPosition.dx;
+          dragDuration = _latestValue.position;
+        },
+        onHorizontalDragUpdate: (DragUpdateDetails detail) {
+          if (_latestValue.duration == null) return;
+          _cancelAndRestartTimer();
+          lastDx = detail.localPosition.dx;
+          // update progress bar
+          Duration finalDuration = getDragDuration();
+
+          setState(() {
+            updateDragDuration = finalDuration;
+          });
+        },
+        onHorizontalDragCancel: (){
+          startDx = null;
+          lastDx = null;
+          dragDuration = null;
+          setState(() {
+            updateDragDuration = null;
+          });
+        },
+        onHorizontalDragEnd: (DragEndDetails detail) {
+          if (startDx != null && lastDx != null && _latestValue.duration != null && dragDuration != null) {
+            Duration finalDuration = getDragDuration();
+            chewieController.seekTo(finalDuration);
+          }
+          startDx = null;
+          lastDx = null;
+          dragDuration = null;
+          setState(() {
+            updateDragDuration = null;
+          });
+        },
         child: AbsorbPointer(
           absorbing: _hideStuff,
           child: Stack(
@@ -78,8 +217,10 @@ class _MaterialControlsState extends State<I2MaterialControls> {
               ),
               Positioned(
                 child: _buildTopBar(context),
-                top: 20,
+                top: MediaQuery.of(context).padding.top,
               ),
+              _buildDragProgress(),
+              _buildVerticalWidget(),
             ],
           )
         ),
@@ -87,6 +228,17 @@ class _MaterialControlsState extends State<I2MaterialControls> {
     );
   }
 
+  @override
+  void initState() {
+    super.initState();
+    _initState();
+  }
+
+  void _initState() async {
+    savedBright = await Screen.brightness;
+    FlutterVolume.disableUI();
+  }
+
   @override
   void dispose() {
     _dispose();
@@ -94,6 +246,7 @@ class _MaterialControlsState extends State<I2MaterialControls> {
   }
 
   void _dispose() async {
+    Screen.setBrightness(savedBright);
     controller.removeListener(_updateState);
     _hideTimer?.cancel();
     _initTimer?.cancel();
@@ -114,6 +267,82 @@ class _MaterialControlsState extends State<I2MaterialControls> {
     super.didChangeDependencies();
   }
 
+  Duration getDragDuration() {
+    if (lastDx - startDx > 0) {
+      // 前进
+      int forwardSec;
+      if (_latestValue.duration.inSeconds > 90) {
+        forwardSec = ((lastDx - startDx) / MediaQuery.of(context).size.width * 90).toInt();
+      } else {
+        forwardSec = ((lastDx - startDx) / MediaQuery.of(context).size.width * _latestValue.duration.inSeconds * 0.8).toInt();
+      }
+      Duration duration = dragDuration + Duration(seconds: forwardSec);
+      return duration >= _latestValue.duration ? _latestValue.duration : duration;
+    } else {
+      // 后退
+      int backwardSec;
+      if (_latestValue.duration.inSeconds > 90) {
+        backwardSec = ((lastDx - startDx) * -1 / MediaQuery.of(context).size.width * 90).toInt();
+      } else {
+        backwardSec = ((lastDx - startDx) * -1 / MediaQuery.of(context).size.width * _latestValue.duration.inSeconds * 0.8).toInt();
+      }
+      Duration duration = (Duration(seconds: backwardSec) > dragDuration) ? Duration.zero : dragDuration - Duration(seconds: backwardSec);
+      return duration;
+    }
+  }
+
+  Widget _buildDragProgress() {
+    final position = updateDragDuration ?? (_latestValue != null && _latestValue.position != null
+        ? _latestValue.position
+        : Duration.zero);
+    return Offstage(
+      offstage: updateDragDuration == null,
+      child: Align(
+        alignment: Alignment.center,
+        child: Container(
+          width: 96,
+          height: 34,
+          decoration: BoxDecoration(
+            color: Color(0xB0000000),
+            borderRadius: BorderRadius.circular(4),
+          ),
+          alignment: Alignment.center,
+          child: Text("${formatDuration(position)}/${formatDuration(_latestValue.duration)}", style: TextStyle(color: Colors.white, fontSize: 12),),
+        ),
+      ),
+    );
+  }
+
+  Widget _buildVerticalWidget() {
+//    ((endDy - startDy) / widgetHeight * 100).toStringAsFixed(2)
+    // 正方圆角
+    return Offstage(
+      offstage: _verticalMode == null,
+      child: Align(
+        alignment: Alignment.center,
+        child: Container(
+          width: 80,
+          height: 80,
+          decoration: BoxDecoration(
+            color: Color(0xB0000000),
+            borderRadius: BorderRadius.circular(4),
+          ),
+          alignment: Alignment.center,
+          child: Column(
+            mainAxisAlignment: MainAxisAlignment.center,
+            mainAxisSize: MainAxisSize.max,
+            children: <Widget>[
+              Icon(_verticalMode == VerticalMode.Volume ? Icons.volume_up : Icons.brightness_6, color: Colors.white, size: 24,),
+              Padding(
+                padding: const EdgeInsets.only(top: 10),
+                child: Text("${valueText}%", style: TextStyle(color: Colors.white, fontSize: 15,),),
+              ),
+            ],
+          ),
+        ),
+      ),
+    );
+  }
 
   AnimatedOpacity _buildTopBar(
       BuildContext context,
@@ -301,9 +530,9 @@ class _MaterialControlsState extends State<I2MaterialControls> {
   }
 
   Widget _buildPosition(Color iconColor) {
-    final position = _latestValue != null && _latestValue.position != null
+    final position = updateDragDuration ?? (_latestValue != null && _latestValue.position != null
         ? _latestValue.position
-        : Duration.zero;
+        : Duration.zero);
     final duration = _latestValue != null && _latestValue.duration != null
         ? _latestValue.duration
         : Duration.zero;
@@ -461,6 +690,7 @@ class _MaterialControlsState extends State<I2MaterialControls> {
                 handleColor: Color(0xFFC7000B),
                 bufferedColor:  Color(0x5AC7000B),
                 backgroundColor: Color(0x5AFFFFFF)),
+        millionSec: updateDragDuration?.inMilliseconds,
       ),
     );
   }

+ 6 - 2
lib/src/material_progress_bar.dart

@@ -10,6 +10,7 @@ class MaterialVideoProgressBar extends StatefulWidget {
     this.onDragEnd,
     this.onDragStart,
     this.onDragUpdate,
+    this.millionSec
   }) : colors = colors ?? ChewieProgressColors();
 
   final VideoPlayerController controller;
@@ -17,6 +18,7 @@ class MaterialVideoProgressBar extends StatefulWidget {
   final Function() onDragStart;
   final Function() onDragEnd;
   final Function() onDragUpdate;
+  final int millionSec;
 
   @override
   _VideoProgressBarState createState() {
@@ -68,6 +70,7 @@ class _VideoProgressBarState extends State<MaterialVideoProgressBar> {
             painter: _ProgressBarPainter(
               controller.value,
               widget.colors,
+              widget.millionSec
             ),
           ),
         ),
@@ -115,10 +118,11 @@ class _VideoProgressBarState extends State<MaterialVideoProgressBar> {
 }
 
 class _ProgressBarPainter extends CustomPainter {
-  _ProgressBarPainter(this.value, this.colors);
+  _ProgressBarPainter(this.value, this.colors, this.millionSec);
 
   VideoPlayerValue value;
   ChewieProgressColors colors;
+  int millionSec;
 
   @override
   bool shouldRepaint(CustomPainter painter) {
@@ -143,7 +147,7 @@ class _ProgressBarPainter extends CustomPainter {
       return;
     }
     final double playedPartPercent =
-        value.position.inMilliseconds / value.duration.inMilliseconds;
+        (millionSec ?? value.position.inMilliseconds) / value.duration.inMilliseconds;
     final double playedPart =
         playedPartPercent > 1 ? size.width : playedPartPercent * size.width;
     for (DurationRange range in value.buffered) {

+ 5 - 0
pubspec.yaml

@@ -14,10 +14,15 @@ dependencies:
   open_iconic_flutter: ">=0.3.0 <0.4.0"
   video_player: ">=0.7.0 <0.11.0"
   wakelock: ">=0.1.2 <0.2.0"
+  screen: "0.0.5"
   orientation:
     git:
       url: https://github.com/hwh97/flutter_orientation.git
 
+  sys_volume:
+    git:
+      url: https://github.com/hwh97/flutter_volume.git
+
   flutter:
     sdk: flutter