fix: audio null 、 播放器面板响应式优化
This commit is contained in:
@ -48,25 +48,26 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
with TickerProviderStateMixin {
|
||||
late AnimationController animationController;
|
||||
late VideoController videoController;
|
||||
final PLVideoPlayerController _ctr = Get.put(PLVideoPlayerController());
|
||||
|
||||
bool _mountSeekBackwardButton = false;
|
||||
bool _mountSeekForwardButton = false;
|
||||
bool _hideSeekBackwardButton = false;
|
||||
bool _hideSeekForwardButton = false;
|
||||
// bool _mountSeekBackwardButton = false;
|
||||
// bool _mountSeekForwardButton = false;
|
||||
// bool _hideSeekBackwardButton = false;
|
||||
// bool _hideSeekForwardButton = false;
|
||||
|
||||
double _brightnessValue = 0.0;
|
||||
bool _brightnessIndicator = false;
|
||||
// double _brightnessValue = 0.0;
|
||||
// bool _brightnessIndicator = false;
|
||||
Timer? _brightnessTimer;
|
||||
|
||||
double _volumeValue = 0.0;
|
||||
bool _volumeIndicator = false;
|
||||
// double _volumeValue = 0.0;
|
||||
// bool _volumeIndicator = false;
|
||||
Timer? _volumeTimer;
|
||||
|
||||
double _distance = 0.0;
|
||||
// 初始手指落下位置
|
||||
double _initTapPositoin = 0.0;
|
||||
|
||||
bool _volumeInterceptEventStream = false;
|
||||
// bool _volumeInterceptEventStream = false;
|
||||
|
||||
Box setting = GStrorage.setting;
|
||||
late FullScreenMode mode;
|
||||
@ -75,15 +76,11 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
late bool enableBackgroundPlay;
|
||||
|
||||
void onDoubleTapSeekBackward() {
|
||||
setState(() {
|
||||
_mountSeekBackwardButton = true;
|
||||
});
|
||||
_ctr.onDoubleTapSeekBackward();
|
||||
}
|
||||
|
||||
void onDoubleTapSeekForward() {
|
||||
setState(() {
|
||||
_mountSeekForwardButton = true;
|
||||
});
|
||||
_ctr.onDoubleTapSeekForward();
|
||||
}
|
||||
|
||||
// 双击播放、暂停
|
||||
@ -135,12 +132,10 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
Future.microtask(() async {
|
||||
try {
|
||||
FlutterVolumeController.showSystemUI = true;
|
||||
_volumeValue = (await FlutterVolumeController.getVolume())!;
|
||||
_ctr.volumeValue.value = (await FlutterVolumeController.getVolume())!;
|
||||
FlutterVolumeController.addListener((value) {
|
||||
if (mounted && !_volumeInterceptEventStream) {
|
||||
setState(() {
|
||||
_volumeValue = value;
|
||||
});
|
||||
if (mounted && !_ctr.volumeInterceptEventStream.value) {
|
||||
_ctr.volumeValue.value = value;
|
||||
}
|
||||
});
|
||||
} catch (_) {}
|
||||
@ -148,12 +143,10 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
|
||||
Future.microtask(() async {
|
||||
try {
|
||||
_brightnessValue = await ScreenBrightness().current;
|
||||
_ctr.brightnessValue.value = await ScreenBrightness().current;
|
||||
ScreenBrightness().onCurrentBrightnessChanged.listen((value) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_brightnessValue = value;
|
||||
});
|
||||
_ctr.brightnessValue.value = value;
|
||||
}
|
||||
});
|
||||
} catch (_) {}
|
||||
@ -165,18 +158,14 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
FlutterVolumeController.showSystemUI = false;
|
||||
await FlutterVolumeController.setVolume(value);
|
||||
} catch (_) {}
|
||||
setState(() {
|
||||
_volumeValue = value;
|
||||
_volumeIndicator = true;
|
||||
_volumeInterceptEventStream = true;
|
||||
});
|
||||
_ctr.volumeValue.value = value;
|
||||
_ctr.volumeIndicator.value = true;
|
||||
_ctr.volumeInterceptEventStream.value = true;
|
||||
_volumeTimer?.cancel();
|
||||
_volumeTimer = Timer(const Duration(milliseconds: 200), () {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_volumeIndicator = false;
|
||||
_volumeInterceptEventStream = false;
|
||||
});
|
||||
_ctr.volumeIndicator.value = false;
|
||||
_ctr.volumeInterceptEventStream.value = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -185,15 +174,11 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
try {
|
||||
await ScreenBrightness().setScreenBrightness(value);
|
||||
} catch (_) {}
|
||||
setState(() {
|
||||
_brightnessIndicator = true;
|
||||
});
|
||||
_ctr.brightnessIndicator.value = true;
|
||||
_brightnessTimer?.cancel();
|
||||
_brightnessTimer = Timer(const Duration(milliseconds: 200), () {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_brightnessIndicator = false;
|
||||
});
|
||||
_ctr.brightnessIndicator.value = false;
|
||||
}
|
||||
});
|
||||
widget.controller.brightness.value = value;
|
||||
@ -322,103 +307,107 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
),
|
||||
|
||||
/// 音量🔊 控制条展示
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: AnimatedOpacity(
|
||||
curve: Curves.easeInOut,
|
||||
opacity: _volumeIndicator ? 1.0 : 0.0,
|
||||
duration: const Duration(milliseconds: 150),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0x88000000),
|
||||
borderRadius: BorderRadius.circular(64.0),
|
||||
),
|
||||
height: 34.0,
|
||||
width: 70.0,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
height: 34.0,
|
||||
width: 28.0,
|
||||
alignment: Alignment.centerRight,
|
||||
child: Icon(
|
||||
_volumeValue == 0.0
|
||||
? Icons.volume_off
|
||||
: _volumeValue < 0.5
|
||||
? Icons.volume_down
|
||||
: Icons.volume_up,
|
||||
color: const Color(0xFFFFFFFF),
|
||||
size: 20.0,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'${(_volumeValue * 100.0).round()}%',
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontSize: 13.0,
|
||||
color: Color(0xFFFFFFFF),
|
||||
Obx(
|
||||
() => Align(
|
||||
alignment: Alignment.center,
|
||||
child: AnimatedOpacity(
|
||||
curve: Curves.easeInOut,
|
||||
opacity: _ctr.volumeIndicator.value ? 1.0 : 0.0,
|
||||
duration: const Duration(milliseconds: 150),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0x88000000),
|
||||
borderRadius: BorderRadius.circular(64.0),
|
||||
),
|
||||
height: 34.0,
|
||||
width: 70.0,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
height: 34.0,
|
||||
width: 28.0,
|
||||
alignment: Alignment.centerRight,
|
||||
child: Icon(
|
||||
_ctr.volumeValue.value == 0.0
|
||||
? Icons.volume_off
|
||||
: _ctr.volumeValue.value < 0.5
|
||||
? Icons.volume_down
|
||||
: Icons.volume_up,
|
||||
color: const Color(0xFFFFFFFF),
|
||||
size: 20.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 6.0),
|
||||
],
|
||||
Expanded(
|
||||
child: Text(
|
||||
'${(_ctr.volumeValue.value * 100.0).round()}%',
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontSize: 13.0,
|
||||
color: Color(0xFFFFFFFF),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 6.0),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
/// 亮度🌞 控制条展示
|
||||
Align(
|
||||
alignment: Alignment.center,
|
||||
child: AnimatedOpacity(
|
||||
curve: Curves.easeInOut,
|
||||
opacity: _brightnessIndicator ? 1.0 : 0.0,
|
||||
duration: const Duration(milliseconds: 150),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0x88000000),
|
||||
borderRadius: BorderRadius.circular(64.0),
|
||||
),
|
||||
height: 34.0,
|
||||
width: 70.0,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
height: 30.0,
|
||||
width: 28.0,
|
||||
alignment: Alignment.centerRight,
|
||||
child: Icon(
|
||||
_brightnessValue < 1.0 / 3.0
|
||||
? Icons.brightness_low
|
||||
: _brightnessValue < 2.0 / 3.0
|
||||
? Icons.brightness_medium
|
||||
: Icons.brightness_high,
|
||||
color: const Color(0xFFFFFFFF),
|
||||
size: 18.0,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 2.0),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'${(_brightnessValue * 100.0).round()}%',
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontSize: 13.0,
|
||||
color: Color(0xFFFFFFFF),
|
||||
Obx(
|
||||
() => Align(
|
||||
alignment: Alignment.center,
|
||||
child: AnimatedOpacity(
|
||||
curve: Curves.easeInOut,
|
||||
opacity: _ctr.brightnessIndicator.value ? 1.0 : 0.0,
|
||||
duration: const Duration(milliseconds: 150),
|
||||
child: Container(
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0x88000000),
|
||||
borderRadius: BorderRadius.circular(64.0),
|
||||
),
|
||||
height: 34.0,
|
||||
width: 70.0,
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Container(
|
||||
height: 30.0,
|
||||
width: 28.0,
|
||||
alignment: Alignment.centerRight,
|
||||
child: Icon(
|
||||
_ctr.brightnessValue.value < 1.0 / 3.0
|
||||
? Icons.brightness_low
|
||||
: _ctr.brightnessValue.value < 2.0 / 3.0
|
||||
? Icons.brightness_medium
|
||||
: Icons.brightness_high,
|
||||
color: const Color(0xFFFFFFFF),
|
||||
size: 18.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 6.0),
|
||||
],
|
||||
const SizedBox(width: 2.0),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'${(_ctr.brightnessValue.value * 100.0).round()}%',
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
fontSize: 13.0,
|
||||
color: Color(0xFFFFFFFF),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 6.0),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@ -525,7 +514,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
}
|
||||
if (tapPosition < sectionWidth) {
|
||||
// 左边区域 👈
|
||||
final brightness = _brightnessValue - delta / 100.0;
|
||||
final brightness = _ctr.brightnessValue.value - delta / 100.0;
|
||||
final result = brightness.clamp(0.0, 1.0);
|
||||
setBrightness(result);
|
||||
} else if (tapPosition < sectionWidth * 2) {
|
||||
@ -548,7 +537,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
_distance = dy;
|
||||
} else {
|
||||
// 右边区域 👈
|
||||
final volume = _volumeValue - delta / 100.0;
|
||||
final volume = _ctr.volumeValue.value - delta / 100.0;
|
||||
final result = volume.clamp(0.0, 1.0);
|
||||
setVolume(result);
|
||||
}
|
||||
@ -704,103 +693,129 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
||||
}),
|
||||
|
||||
/// 点击 快进/快退
|
||||
if (_mountSeekBackwardButton || _mountSeekForwardButton)
|
||||
Positioned.fill(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _mountSeekBackwardButton
|
||||
? TweenAnimationBuilder<double>(
|
||||
tween: Tween<double>(
|
||||
begin: 0.0,
|
||||
end: _hideSeekBackwardButton ? 0.0 : 1.0,
|
||||
),
|
||||
duration: const Duration(milliseconds: 500),
|
||||
builder: (context, value, child) => Opacity(
|
||||
opacity: value,
|
||||
child: child,
|
||||
),
|
||||
onEnd: () {
|
||||
if (_hideSeekBackwardButton) {
|
||||
setState(() {
|
||||
_hideSeekBackwardButton = false;
|
||||
_mountSeekBackwardButton = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
child: BackwardSeekIndicator(
|
||||
onChanged: (value) {
|
||||
// _seekBarDeltaValueNotifier.value = -value;
|
||||
Obx(
|
||||
() => Visibility(
|
||||
visible: _ctr.mountSeekBackwardButton.value ||
|
||||
_ctr.mountSeekForwardButton.value,
|
||||
child: Positioned.fill(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _ctr.mountSeekBackwardButton.value
|
||||
? TweenAnimationBuilder<double>(
|
||||
tween: Tween<double>(
|
||||
begin: 0.0,
|
||||
end:
|
||||
_ctr.hideSeekBackwardButton.value ? 0.0 : 1.0,
|
||||
),
|
||||
duration: const Duration(milliseconds: 500),
|
||||
builder: (context, value, child) => Opacity(
|
||||
opacity: value,
|
||||
child: child,
|
||||
),
|
||||
onEnd: () {
|
||||
if (_ctr.hideSeekBackwardButton.value) {
|
||||
_ctr.hideSeekBackwardButton.value = false;
|
||||
_ctr.mountSeekBackwardButton.value = false;
|
||||
}
|
||||
},
|
||||
onSubmitted: (value) {
|
||||
setState(() {
|
||||
_hideSeekBackwardButton = true;
|
||||
});
|
||||
Player player =
|
||||
widget.controller.videoPlayerController!;
|
||||
var result = player.state.position - value;
|
||||
result = result.clamp(
|
||||
Duration.zero,
|
||||
player.state.duration,
|
||||
);
|
||||
player.seek(result);
|
||||
widget.controller.play();
|
||||
},
|
||||
),
|
||||
)
|
||||
: const SizedBox(),
|
||||
),
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
width: MediaQuery.of(context).size.width / 4,
|
||||
child: BackwardSeekIndicator(
|
||||
onChanged: (value) {
|
||||
// _seekBarDeltaValueNotifier.value = -value;
|
||||
},
|
||||
onSubmitted: (value) {
|
||||
_ctr.hideSeekBackwardButton.value = true;
|
||||
Player player =
|
||||
widget.controller.videoPlayerController!;
|
||||
var result = player.state.position - value;
|
||||
result = result.clamp(
|
||||
Duration.zero,
|
||||
player.state.duration,
|
||||
);
|
||||
player.seek(result);
|
||||
widget.controller.play();
|
||||
},
|
||||
),
|
||||
)
|
||||
: const SizedBox(),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: _mountSeekForwardButton
|
||||
? TweenAnimationBuilder<double>(
|
||||
tween: Tween<double>(
|
||||
begin: 0.0,
|
||||
end: _hideSeekForwardButton ? 0.0 : 1.0,
|
||||
),
|
||||
duration: const Duration(milliseconds: 500),
|
||||
builder: (context, value, child) => Opacity(
|
||||
opacity: value,
|
||||
child: child,
|
||||
),
|
||||
onEnd: () {
|
||||
if (_hideSeekForwardButton) {
|
||||
setState(() {
|
||||
_hideSeekForwardButton = false;
|
||||
_mountSeekForwardButton = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
child: ForwardSeekIndicator(
|
||||
onChanged: (value) {
|
||||
// _seekBarDeltaValueNotifier.value = value;
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
width: MediaQuery.of(context).size.width / 4,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: _ctr.mountSeekForwardButton.value
|
||||
? TweenAnimationBuilder<double>(
|
||||
tween: Tween<double>(
|
||||
begin: 0.0,
|
||||
end: _ctr.hideSeekForwardButton.value ? 0.0 : 1.0,
|
||||
),
|
||||
duration: const Duration(milliseconds: 500),
|
||||
builder: (context, value, child) => Opacity(
|
||||
opacity: value,
|
||||
child: child,
|
||||
),
|
||||
onEnd: () {
|
||||
if (_ctr.hideSeekForwardButton.value) {
|
||||
_ctr.hideSeekForwardButton.value = false;
|
||||
_ctr.mountSeekForwardButton.value = false;
|
||||
}
|
||||
},
|
||||
onSubmitted: (value) {
|
||||
setState(() {
|
||||
_hideSeekForwardButton = true;
|
||||
});
|
||||
Player player =
|
||||
widget.controller.videoPlayerController!;
|
||||
var result = player.state.position + value;
|
||||
result = result.clamp(
|
||||
Duration.zero,
|
||||
player.state.duration,
|
||||
);
|
||||
player.seek(result);
|
||||
widget.controller.play();
|
||||
},
|
||||
),
|
||||
)
|
||||
: const SizedBox(),
|
||||
),
|
||||
],
|
||||
child: ForwardSeekIndicator(
|
||||
onChanged: (value) {
|
||||
// _seekBarDeltaValueNotifier.value = value;
|
||||
},
|
||||
onSubmitted: (value) {
|
||||
_ctr.hideSeekForwardButton.value = true;
|
||||
Player player =
|
||||
widget.controller.videoPlayerController!;
|
||||
var result = player.state.position + value;
|
||||
result = result.clamp(
|
||||
Duration.zero,
|
||||
player.state.duration,
|
||||
);
|
||||
player.seek(result);
|
||||
widget.controller.play();
|
||||
},
|
||||
),
|
||||
)
|
||||
: const SizedBox(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class PLVideoPlayerController extends GetxController {
|
||||
RxBool mountSeekBackwardButton = false.obs;
|
||||
RxBool mountSeekForwardButton = false.obs;
|
||||
RxBool hideSeekBackwardButton = false.obs;
|
||||
RxBool hideSeekForwardButton = false.obs;
|
||||
|
||||
RxDouble brightnessValue = 0.0.obs;
|
||||
RxBool brightnessIndicator = false.obs;
|
||||
|
||||
RxDouble volumeValue = 0.0.obs;
|
||||
RxBool volumeIndicator = false.obs;
|
||||
|
||||
RxDouble distance = 0.0.obs;
|
||||
// 初始手指落下位置
|
||||
RxDouble initTapPositoin = 0.0.obs;
|
||||
|
||||
RxBool volumeInterceptEventStream = false.obs;
|
||||
|
||||
// 双击快进 展示样式
|
||||
void onDoubleTapSeekForward() {
|
||||
mountSeekForwardButton.value = true;
|
||||
}
|
||||
|
||||
void onDoubleTapSeekBackward() {
|
||||
mountSeekBackwardButton.value = true;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user