feat: 全屏播放
This commit is contained in:
@ -1,6 +1,7 @@
|
||||
import 'dart:async';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/painting.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
@ -53,6 +54,9 @@ class PlPlayerController {
|
||||
final Rx<bool> _showBrightnessStatus = false.obs;
|
||||
final Rx<bool> _doubleSpeedStatus = false.obs;
|
||||
final Rx<bool> _controlsLock = false.obs;
|
||||
final Rx<bool> _isFullScreen = false.obs;
|
||||
|
||||
final Rx<String> _direction = 'horizontal'.obs;
|
||||
|
||||
Rx<bool> videoFitChanged = false.obs;
|
||||
final Rx<BoxFit> _videoFit = Rx(BoxFit.fill);
|
||||
@ -82,6 +86,8 @@ class PlPlayerController {
|
||||
BoxFit.scaleDown
|
||||
];
|
||||
|
||||
PreferredSizeWidget? headerControl;
|
||||
|
||||
/// 数据加载监听
|
||||
Stream<DataStatus> get onDataStatusChanged => dataStatus.status.stream;
|
||||
|
||||
@ -160,6 +166,12 @@ class PlPlayerController {
|
||||
/// 屏幕锁 为true时,关闭控制栏
|
||||
Rx<bool> get controlsLock => _controlsLock;
|
||||
|
||||
/// 全屏状态
|
||||
Rx<bool> get isFullScreen => _isFullScreen;
|
||||
|
||||
/// 全屏方向
|
||||
Rx<String> get direction => _direction;
|
||||
|
||||
PlPlayerController({
|
||||
// 直播间 传false 关闭控制栏
|
||||
this.controlsEnabled = true,
|
||||
@ -197,6 +209,9 @@ class PlPlayerController {
|
||||
double? width,
|
||||
double? height,
|
||||
Duration? duration,
|
||||
// 方向
|
||||
String? direction,
|
||||
// 全屏模式
|
||||
}) async {
|
||||
try {
|
||||
_autoPlay = autoplay;
|
||||
@ -207,6 +222,8 @@ class PlPlayerController {
|
||||
_playbackSpeed.value = speed;
|
||||
// 初始化数据加载状态
|
||||
dataStatus.status.value = DataStatus.loading;
|
||||
// 初始化全屏方向
|
||||
_direction.value = direction ?? 'horizontal';
|
||||
|
||||
if (_videoPlayerController != null &&
|
||||
_videoPlayerController!.state.playing) {
|
||||
@ -624,6 +641,10 @@ class PlPlayerController {
|
||||
showControls.value = !val;
|
||||
}
|
||||
|
||||
void toggleFullScreen(bool val) {
|
||||
_isFullScreen.value = val;
|
||||
}
|
||||
|
||||
/// 截屏
|
||||
Future screenshot() async {
|
||||
final Uint8List? screenshot =
|
||||
|
||||
@ -8,3 +8,5 @@ export './models/data_status.dart';
|
||||
export './widgets/common_btn.dart';
|
||||
export './models/play_speed.dart';
|
||||
export './widgets/app_bar_ani.dart';
|
||||
export './utils/fullscreen.dart';
|
||||
export './utils.dart';
|
||||
|
||||
9
lib/plugin/pl_player/models/fullscreen_mode.dart
Normal file
9
lib/plugin/pl_player/models/fullscreen_mode.dart
Normal file
@ -0,0 +1,9 @@
|
||||
// 全屏模式
|
||||
enum FullScreenMode {
|
||||
// 根据内容自适应
|
||||
auto,
|
||||
// 始终竖屏
|
||||
vertical,
|
||||
// 始终横屏
|
||||
horizontal
|
||||
}
|
||||
40
lib/plugin/pl_player/utils/fullscreen.dart
Normal file
40
lib/plugin/pl_player/utils/fullscreen.dart
Normal file
@ -0,0 +1,40 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:device_info_plus/device_info_plus.dart';
|
||||
import 'package:auto_orientation/auto_orientation.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
//横屏
|
||||
/// 低版本xcode不支持auto_orientation
|
||||
Future<void> landScape() async {
|
||||
if (Platform.isAndroid || Platform.isIOS) {
|
||||
await AutoOrientation.landscapeAutoMode(forceSensor: true);
|
||||
}
|
||||
}
|
||||
|
||||
//竖屏
|
||||
Future<void> verticalScreen() async {
|
||||
await SystemChrome.setPreferredOrientations([
|
||||
DeviceOrientation.portraitUp,
|
||||
]);
|
||||
}
|
||||
|
||||
Future<void> enterFullScreen() async {
|
||||
await SystemChrome.setEnabledSystemUIMode(
|
||||
SystemUiMode.immersiveSticky,
|
||||
);
|
||||
}
|
||||
|
||||
//退出全屏显示
|
||||
Future<void> exitFullScreen() async {
|
||||
late SystemUiMode mode;
|
||||
if ((Platform.isAndroid &&
|
||||
(await DeviceInfoPlugin().androidInfo).version.sdkInt >= 29) ||
|
||||
!Platform.isAndroid) {
|
||||
mode = SystemUiMode.edgeToEdge;
|
||||
} else {
|
||||
mode = SystemUiMode.manual;
|
||||
}
|
||||
await SystemChrome.setEnabledSystemUIMode(mode,
|
||||
overlays: [SystemUiOverlay.top, SystemUiOverlay.bottom]);
|
||||
}
|
||||
@ -75,6 +75,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
animationController = AnimationController(
|
||||
vsync: this, duration: const Duration(milliseconds: 300));
|
||||
videoController = widget.controller.videoController!;
|
||||
widget.controller.headerControl = widget.headerControl;
|
||||
|
||||
Future.microtask(() async {
|
||||
try {
|
||||
@ -149,6 +150,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
print('🌹🌹🌹🌹🌹:33333');
|
||||
final _ = widget.controller;
|
||||
Color colorTheme = Theme.of(context).colorScheme.primary;
|
||||
TextStyle subTitleStyle = const TextStyle(
|
||||
@ -387,6 +389,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
// 双击左边区域 👈
|
||||
onDoubleTapSeekBackward();
|
||||
} else if (tapPosition < sectionWidth * 2) {
|
||||
print('🌹🌹🌹🌹🌹:333356555553');
|
||||
if (_.playerStatus.status.value == PlayerStatus.playing) {
|
||||
_.togglePlay();
|
||||
} else {
|
||||
@ -443,15 +446,16 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
Obx(
|
||||
() => Column(
|
||||
children: [
|
||||
ClipRect(
|
||||
clipBehavior: Clip.hardEdge,
|
||||
child: AppBarAni(
|
||||
controller: animationController,
|
||||
visible: !_.controlsLock.value && _.showControls.value,
|
||||
position: 'top',
|
||||
child: widget.headerControl!,
|
||||
if (widget.headerControl != null)
|
||||
ClipRect(
|
||||
clipBehavior: Clip.hardEdge,
|
||||
child: AppBarAni(
|
||||
controller: animationController,
|
||||
visible: !_.controlsLock.value && _.showControls.value,
|
||||
position: 'top',
|
||||
child: widget.headerControl!,
|
||||
),
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
ClipRect(
|
||||
clipBehavior: Clip.hardEdge,
|
||||
|
||||
@ -5,8 +5,6 @@ import 'package:get/get.dart';
|
||||
import 'package:pilipala/plugin/pl_player/index.dart';
|
||||
import 'package:pilipala/plugin/pl_player/widgets/play_pause_btn.dart';
|
||||
|
||||
import '../utils.dart';
|
||||
|
||||
class BottomControl extends StatelessWidget implements PreferredSizeWidget {
|
||||
final PlPlayerController? controller;
|
||||
const BottomControl({this.controller, Key? key}) : super(key: key);
|
||||
@ -138,14 +136,52 @@ class BottomControl extends StatelessWidget implements PreferredSizeWidget {
|
||||
// ),
|
||||
// const SizedBox(width: 4),
|
||||
// 全屏
|
||||
ComBtn(
|
||||
icon: const Icon(
|
||||
FontAwesomeIcons.expand,
|
||||
size: 15,
|
||||
color: Colors.white,
|
||||
),
|
||||
fuc: () => {},
|
||||
),
|
||||
Obx(() => ComBtn(
|
||||
icon: Icon(
|
||||
_.isFullScreen.value
|
||||
? FontAwesomeIcons.a
|
||||
: FontAwesomeIcons.expand,
|
||||
size: 15,
|
||||
color: Colors.white,
|
||||
),
|
||||
fuc: () async {
|
||||
if (!_.isFullScreen.value) {
|
||||
/// 按照视频宽高比决定全屏方向
|
||||
if (_.direction.value == 'horizontal') {
|
||||
/// 进入全屏
|
||||
await enterFullScreen();
|
||||
// 横屏
|
||||
await landScape();
|
||||
} else {
|
||||
// 竖屏
|
||||
await verticalScreen();
|
||||
}
|
||||
|
||||
_.toggleFullScreen(true);
|
||||
var result = await showDialog(
|
||||
context: Get.context!,
|
||||
builder: (context) => Dialog.fullscreen(
|
||||
backgroundColor: Colors.black,
|
||||
child: PLVideoPlayer(
|
||||
controller: _,
|
||||
headerControl: _.headerControl,
|
||||
),
|
||||
),
|
||||
);
|
||||
if (result == null) {
|
||||
// 退出全屏
|
||||
exitFullScreen();
|
||||
await verticalScreen();
|
||||
_.toggleFullScreen(false);
|
||||
}
|
||||
} else {
|
||||
Get.back();
|
||||
exitFullScreen();
|
||||
await verticalScreen();
|
||||
_.toggleFullScreen(false);
|
||||
}
|
||||
},
|
||||
)),
|
||||
],
|
||||
),
|
||||
],
|
||||
|
||||
Reference in New Issue
Block a user