Prechádzať zdrojové kódy

增加了几个配置选项,用于设置默认控制器的一些行为

Caijinglong 6 rokov pred
rodič
commit
39399f6382

+ 2 - 1
README.md

@@ -236,7 +236,8 @@ await controller.dispose(); //这个方法调用后,当前控制器理论上不
   - [x] 单击显示/隐藏界面
   - [x] 双击播放/暂停
   - [ ] 拖动进度条快速调节进度
-  - [ ] 使用选项切换音量的控制是系统音量还是资源音量
+  - [x] 使用选项切换音量的控制是系统音量还是资源音量
+  - [x] 允许根据情况禁用各种控制手势
 - [x] 根据视频角度自动旋转
 - [x] 保证图片宽高比不失真
 - [x] 允许自定义控制器 UI

+ 31 - 9
android/src/main/java/top/kikt/ijkplayer/IjkplayerPlugin.kt

@@ -2,7 +2,6 @@ package top.kikt.ijkplayer
 
 import android.content.Context
 import android.media.AudioManager
-import android.os.Build
 import io.flutter.plugin.common.MethodCall
 import io.flutter.plugin.common.MethodChannel
 import io.flutter.plugin.common.MethodChannel.MethodCallHandler
@@ -51,28 +50,51 @@ class IjkplayerPlugin(private val registrar: Registrar) : MethodCallHandler {
                 val volume = getSystemVolume()
                 result.success(volume)
             }
+            "volumeUp" -> {
+                this.volumeUp()
+                val volume = getSystemVolume()
+                result.success(volume)
+            }
+            "volumeDown" -> {
+                this.volumeDown()
+                val volume = getSystemVolume()
+                result.success(volume)
+            }
             else -> result.notImplemented()
         }
     }
 
     private fun getSystemVolume(): Int {
-        return audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
+        val max = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC).toFloat()
+        return (audioManager.getStreamVolume(AudioManager.STREAM_MUSIC).toFloat() / max * 100).toInt()
     }
 
     private fun setVolume(volume: Int) {
         audioManager.apply {
             val max = getStreamMaxVolume(AudioManager.STREAM_MUSIC)
-            val min = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
-                getStreamMinVolume(AudioManager.STREAM_MUSIC)
-            } else {
-                0
+
+            val step = 100.toFloat() / max.toFloat()
+
+            val current = getSystemVolume()
+
+            val progress = current * step
+
+            if (volume > progress) {
+                volumeDown()
+            } else if (volume < progress) {
+                volumeUp()
             }
-            val diff: Float = (max - min).toFloat()
-            val target: Int = ((min + diff) * volume).toInt()
-            setStreamVolume(AudioManager.STREAM_MUSIC, target, 0)
         }
     }
 
+    private fun volumeUp() {
+        audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, AudioManager.FLAG_PLAY_SOUND)
+    }
+
+    private fun volumeDown() {
+        audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_LOWER, AudioManager.FLAG_PLAY_SOUND)
+    }
+
     private val audioManager: AudioManager
         get() = registrar.activity().getSystemService(Context.AUDIO_SERVICE) as AudioManager
 

+ 4 - 4
example/ios/Podfile.lock

@@ -9,8 +9,8 @@ PODS:
 
 DEPENDENCIES:
   - Flutter (from `.symlinks/flutter/ios`)
-  - flutter_ijkplayer (from `/Users/caijinglong/Documents/GitHub/flutter_ijkplayer/ios/flutter_ijkplayer.podspec`)
-  - photo_manager (from `/Users/caijinglong/.pub-cache/hosted/pub.flutter-io.cn/photo_manager-0.3.3/ios/photo_manager.podspec`)
+  - flutter_ijkplayer (from `/Users/cai/Documents/GitHub/flutter_ijkplayer/ios/flutter_ijkplayer.podspec`)
+  - photo_manager (from `/Users/cai/.pub-cache/hosted/pub.flutter-io.cn/photo_manager-0.3.3/ios/photo_manager.podspec`)
 
 SPEC REPOS:
   https://github.com/cocoapods/specs.git:
@@ -20,9 +20,9 @@ EXTERNAL SOURCES:
   Flutter:
     :path: ".symlinks/flutter/ios"
   flutter_ijkplayer:
-    :path: "/Users/caijinglong/Documents/GitHub/flutter_ijkplayer/ios/flutter_ijkplayer.podspec"
+    :path: "/Users/cai/Documents/GitHub/flutter_ijkplayer/ios/flutter_ijkplayer.podspec"
   photo_manager:
-    :path: "/Users/caijinglong/.pub-cache/hosted/pub.flutter-io.cn/photo_manager-0.3.3/ios/photo_manager.podspec"
+    :path: "/Users/cai/.pub-cache/hosted/pub.flutter-io.cn/photo_manager-0.3.3/ios/photo_manager.podspec"
 
 SPEC CHECKSUMS:
   Flutter: 58dd7d1b27887414a370fcccb9e645c08ffd7a6a

+ 11 - 0
example/lib/main.dart

@@ -66,6 +66,7 @@ class HomePageState extends State<HomePage> {
             _buildPlayAssetButton(),
             _buildControllerButtons(),
             _buildVolumeBar(),
+            _buildSystemVolumeButton(),
           ],
         ),
       ),
@@ -222,4 +223,14 @@ class HomePageState extends State<HomePage> {
       },
     );
   }
+
+  _buildSystemVolumeButton() {
+    return FlatButton(
+      child: Text("显示系统音量"),
+      onPressed: () async {
+        var systemVolume = await IjkManager.getSystemVolume();
+        print(systemVolume);
+      },
+    );
+  }
 }

+ 26 - 3
ios/Classes/IjkplayerPlugin.m

@@ -72,15 +72,30 @@ static IjkplayerPlugin *__sharedInstance;
             [self setSystemVolume:volume];
             result(@YES);
         } else if ([@"getSystemVolume" isEqualToString:call.method]) {
-            AVAudioSession *audioSession = [AVAudioSession sharedInstance];
-            CGFloat currentVol = audioSession.outputVolume * 100;
-            result(@((int) currentVol));
+            int currentVol = [self getSystemVolume];
+            result(@(currentVol));
+        } else if ([@"volumeUp" isEqualToString:call.method]) {
+            int currentVol = [self getSystemVolume];
+            [self setSystemVolume: currentVol - 10];
+            currentVol = [self getSystemVolume];
+            result(@(currentVol));
+        } else if ([@"volumeDown" isEqualToString:call.method]) {
+            int currentVol = [self getSystemVolume];
+            [self setSystemVolume: currentVol + 10];
+            currentVol = [self getSystemVolume];
+            result(@(currentVol));
         } else {
             result(FlutterMethodNotImplemented);
         }
     });
 }
 
+- (int) getSystemVolume{
+    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
+    CGFloat currentVol = audioSession.outputVolume * 100;
+    return (int)currentVol;
+}
+
 - (void)setSystemVolume:(int)volume {
     MPVolumeView *volumeView = [[MPVolumeView alloc] init];
     UISlider *volumeViewSlider = nil;
@@ -98,11 +113,19 @@ static IjkplayerPlugin *__sharedInstance;
     UIWindow *window = UIApplication.sharedApplication.keyWindow;
     [window addSubview:volumeView];
 
+    if (targetVolume > 1){
+        targetVolume = 1;
+    } else if(targetVolume < 0){
+        targetVolume = 0;
+    }
+    
     // change system volume, the value is between 0.0f and 1.0f
     [volumeViewSlider setValue:targetVolume animated:NO];
 
     // send UI control event to make the change effect right now. 立即生效
     [volumeViewSlider sendActionsForControlEvents:UIControlEventTouchUpInside];
+    
+    [volumeView removeFromSuperview];
 }
 
 @end

+ 1 - 1
lib/flutter_ijkplayer.dart

@@ -1,5 +1,5 @@
 export 'src/error.dart';
 export 'src/ijkplayer.dart';
 export 'src/video_info.dart';
-export 'src/widget/controller_builder.dart' show DefaultControllerWidget;
+export 'src/widget/controller_widget_builder.dart' show DefaultControllerWidget;
 export 'src/config.dart';

+ 1 - 1
lib/src/controller.dart

@@ -256,7 +256,7 @@ Future<int> _createIjk() async {
 class _IjkPlugin {
   MethodChannel get channel => MethodChannel("top.kikt/ijkplayer/$textureId");
 
-  ///
+  /// texture id
   int textureId;
 
   _IjkPlugin(this.textureId);

+ 0 - 11
lib/src/controller_builder.dart

@@ -1,11 +0,0 @@
-import 'package:flutter/material.dart';
-import 'package:flutter_ijkplayer/flutter_ijkplayer.dart';
-import 'package:flutter_ijkplayer/src/widget/controller_builder.dart';
-
-/// Using mediaController to Construct a Controller UI
-typedef Widget ControllerWidgetBuilder(IjkMediaController controller);
-
-/// default create IJK Controller UI
-Widget defaultBuildIjkControllerWidget(IjkMediaController controller) {
-  return DefaultControllerWidget(controller: controller);
-}

+ 9 - 7
lib/src/ijkplayer.dart

@@ -3,17 +3,19 @@ import 'dart:io';
 
 import 'package:flutter/material.dart';
 import 'package:flutter/services.dart';
-import 'package:flutter_ijkplayer/src/video_info.dart';
-import 'package:flutter_ijkplayer/src/widget/ijkplayer_builder.dart';
 
-import './controller_builder.dart';
-import './error.dart';
+import 'error.dart';
 import 'logutil.dart';
+import 'video_info.dart';
+import 'widget/controller_widget_builder.dart';
+import 'widget/ijkplayer_builder.dart';
+
+part 'controller.dart';
 
-part './controller.dart';
-part './manager.dart';
 part 'ijk_event_channel.dart';
 
+part 'manager.dart';
+
 /// Main Classes of Library
 class IjkPlayer extends StatefulWidget {
   final IjkMediaController mediaController;
@@ -23,7 +25,7 @@ class IjkPlayer extends StatefulWidget {
   /// Main Classes of Library
   const IjkPlayer({
     Key key,
-    this.mediaController,
+    @required this.mediaController,
     this.controllerWidgetBuilder = defaultBuildIjkControllerWidget,
     this.playerBuilder = buildDefaultIjkPlayer,
   }) : super(key: key);

+ 8 - 0
lib/src/manager.dart

@@ -24,4 +24,12 @@ class IjkManager {
   static Future<int> getSystemVolume() async {
     return _globalChannel.invokeMethod("getSystemVolume");
   }
+
+  static Future<int> systemVolumeUp() async {
+    return _globalChannel.invokeMethod("volumeUp");
+  }
+
+  static Future<int> systemVolumeDown() async {
+    return _globalChannel.invokeMethod("volumeDown");
+  }
 }

+ 98 - 22
lib/src/widget/controller_builder.dart → lib/src/widget/controller_widget_builder.dart

@@ -5,16 +5,43 @@ import 'package:flutter_ijkplayer/flutter_ijkplayer.dart';
 import 'package:flutter_ijkplayer/src/logutil.dart';
 import 'package:flutter_ijkplayer/src/widget/progress_bar.dart';
 
+/// Using mediaController to Construct a Controller UI
+typedef Widget ControllerWidgetBuilder(IjkMediaController controller);
+
+/// default create IJK Controller UI
+Widget defaultBuildIjkControllerWidget(IjkMediaController controller) {
+  return DefaultControllerWidget(
+    controller: controller,
+//    verticalGesture: false,
+//    horizontalGesture: false,
+  );
+}
+
 /// Default Controller Widget
 ///
-/// see [IjkPlayer] and []
+/// see [IjkPlayer] and [ControllerWidgetBuilder]
 class DefaultControllerWidget extends StatefulWidget {
   final IjkMediaController controller;
+
+  /// If [doubleTapPlay] is true, can double tap to play or pause media.
   final bool doubleTapPlay;
 
+  /// If [verticalGesture] is false, vertical gesture will be ignored.
+  final bool verticalGesture;
+
+  /// If [horizontalGesture] is false, horizontal gesture will be ignored.
+  final bool horizontalGesture;
+
+  /// Controlling [verticalGesture] is controlling system volume or media volume.
+  final VolumeType volumeType;
+
+  /// The UI of the controller.
   const DefaultControllerWidget({
-    this.controller,
+    @required this.controller,
     this.doubleTapPlay = false,
+    this.verticalGesture = true,
+    this.horizontalGesture = true,
+    this.volumeType = VolumeType.system,
   });
 
   @override
@@ -91,27 +118,16 @@ class _DefaultControllerWidgetState extends State<DefaultControllerWidget> {
       behavior: HitTestBehavior.opaque,
       child: buildContent(),
       onDoubleTap: onDoubleTap(),
-      onHorizontalDragStart: _onHorizontalDragStart,
-      onHorizontalDragUpdate: _onHorizontalDragUpdate,
-      onHorizontalDragEnd: _onHorizontalDragEnd,
-      onVerticalDragStart: _onVerticalDragStart,
-      onVerticalDragUpdate: _onVerticalDragUpdate,
-      onVerticalDragEnd: _onVerticalDragEnd,
+      onHorizontalDragStart: wrapHorizontalGesture(_onHorizontalDragStart),
+      onHorizontalDragUpdate: wrapHorizontalGesture(_onHorizontalDragUpdate),
+      onHorizontalDragEnd: wrapHorizontalGesture(_onHorizontalDragEnd),
+      onVerticalDragStart: wrapVerticalGesture(_onVerticalDragStart),
+      onVerticalDragUpdate: wrapVerticalGesture(_onVerticalDragUpdate),
+      onVerticalDragEnd: wrapVerticalGesture(_onVerticalDragEnd),
       onTap: onTap,
     );
   }
 
-  onTap() => isShow = !isShow;
-
-  Function onDoubleTap() {
-    return widget.doubleTapPlay
-        ? () {
-            LogUtils.log("ondouble tap");
-            controller.playOrPause();
-          }
-        : null;
-  }
-
   Widget buildContent() {
     if (!isShow) {
       return Container();
@@ -181,6 +197,23 @@ class _DefaultControllerWidgetState extends State<DefaultControllerWidget> {
 
   _ProgressCalculator _calculator;
 
+  onTap() => isShow = !isShow;
+
+  Function onDoubleTap() {
+    return widget.doubleTapPlay
+        ? () {
+            LogUtils.log("ondouble tap");
+            controller.playOrPause();
+          }
+        : null;
+  }
+
+  Function wrapHorizontalGesture(Function function) =>
+      widget.horizontalGesture == true ? function : null;
+
+  Function wrapVerticalGesture(Function function) =>
+      widget.verticalGesture == true ? function : null;
+
   void _onHorizontalDragStart(DragStartDetails details) async {
     var videoInfo = await controller.getVideoInfo();
     _calculator = _ProgressCalculator(details, videoInfo);
@@ -227,11 +260,13 @@ class _DefaultControllerWidgetState extends State<DefaultControllerWidget> {
 
   void _onVerticalDragUpdate(DragUpdateDetails details) async {
     if (details.delta.dy > 0) {
-      controller.volume--;
+      volumeDown();
     } else if (details.delta.dy < 0) {
-      controller.volume++;
+      volumeUp();
     }
 
+    var currentVolume = await getVolume();
+
     var column = Column(
       mainAxisAlignment: MainAxisAlignment.center,
       children: <Widget>[
@@ -242,7 +277,7 @@ class _DefaultControllerWidgetState extends State<DefaultControllerWidget> {
         ),
         Padding(
           padding: const EdgeInsets.only(top: 10.0),
-          child: Text(controller.volume.toString()),
+          child: Text(currentVolume.toString()),
         ),
       ],
     );
@@ -253,6 +288,42 @@ class _DefaultControllerWidgetState extends State<DefaultControllerWidget> {
   void _onVerticalDragEnd(DragEndDetails details) {
     hideTipWidget();
   }
+
+  Future<int> getVolume() async {
+    switch (widget.volumeType) {
+      case VolumeType.media:
+        return controller.volume;
+      case VolumeType.system:
+        return controller.getSystemVolume();
+    }
+    return 0;
+  }
+
+  Future<void> volumeUp() async {
+    var volume = await getVolume();
+    volume++;
+    switch (widget.volumeType) {
+      case VolumeType.media:
+        controller.volume = volume;
+        break;
+      case VolumeType.system:
+        await IjkManager.systemVolumeUp();
+        break;
+    }
+  }
+
+  Future<void> volumeDown() async {
+    var volume = await getVolume();
+    volume--;
+    switch (widget.volumeType) {
+      case VolumeType.media:
+        controller.volume = volume;
+        break;
+      case VolumeType.system:
+        await IjkManager.systemVolumeDown();
+        break;
+    }
+  }
 }
 
 class _ProgressCalculator {
@@ -379,3 +450,8 @@ class PortraitController extends StatelessWidget {
     );
   }
 }
+
+enum VolumeType {
+  system,
+  media,
+}