flutter_integrated_whb/lib/customWidget/full_screen_video_page.dart

266 lines
8.2 KiB
Dart
Raw Permalink Normal View History

2025-07-11 11:03:21 +08:00
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
import 'package:flutter/services.dart';
///弹窗组件VideoPlayerPopup
class VideoPlayerPopup extends StatefulWidget {
/// 视频地址
final String videoUrl;
const VideoPlayerPopup({Key? key, required this.videoUrl}) : super(key: key);
@override
State<VideoPlayerPopup> createState() => _VideoPlayerPopupState();
}
class _VideoPlayerPopupState extends State<VideoPlayerPopup> {
late VideoPlayerController _controller;
bool _showControls = true;
@override
void initState() {
super.initState();
_controller = VideoPlayerController.networkUrl(
Uri.parse(widget.videoUrl),
)..initialize().then((_) {
setState(() {});
_controller.play();
});
// 自动隐藏控件
_controller.addListener(() {
if (_controller.value.isPlaying && _showControls) {
Future.delayed(const Duration(seconds: 3), () {
if (_controller.value.isPlaying && mounted) {
setState(() => _showControls = false);
}
});
}
});
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
Widget _buildControls() {
final pos = _controller.value.position;
final dur = _controller.value.duration;
String fmt(Duration d) =>
'${d.inMinutes.remainder(60).toString().padLeft(2, '0')}:'
'${d.inSeconds.remainder(60).toString().padLeft(2, '0')}';
return Positioned.fill(
child: AnimatedOpacity(
opacity: _showControls ? 1 : 0,
duration: const Duration(milliseconds: 300),
child: GestureDetector(
onTap: () => setState(() => _showControls = !_showControls),
child: Container(
color: Colors.black45,
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
// 进度条
Slider(
value: pos.inMilliseconds.toDouble().clamp(0, dur.inMilliseconds.toDouble()),
max: dur.inMilliseconds.toDouble(),
onChanged: (v) {
_controller.seekTo(Duration(milliseconds: v.toInt()));
},
),
// 时间 + 控制按钮
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
child: Row(
children: [
IconButton(
icon: Icon(
_controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
color: Colors.white,
),
onPressed: () {
setState(() {
_controller.value.isPlaying
? _controller.pause()
: _controller.play();
});
},
),
Text(
'${fmt(pos)} / ${fmt(dur)}',
style: const TextStyle(color: Colors.white),
),
const Spacer(),
IconButton(
icon: const Icon(Icons.fullscreen, color: Colors.white),
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (_) => FullScreenVideoPage(
controller: _controller)));
},
),
],
),
),
],
),
),
),
),
);
}
@override
Widget build(BuildContext context) {
return Center(
child: Material(
color: Colors.transparent,
child: Container(
constraints: BoxConstraints(
maxWidth: MediaQuery.of(context).size.width * 0.9,
maxHeight: MediaQuery.of(context).size.height * 0.8,
),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: Stack(
children: [
// 视频内容
if (_controller.value.isInitialized)
AspectRatio(
aspectRatio: _controller.value.aspectRatio,
child: VideoPlayer(_controller),
)
else
const Center(child: CircularProgressIndicator()),
// 关闭按钮
Positioned(
top: 4,
right: 4,
child: IconButton(
icon: const Icon(Icons.close, color: Colors.black54),
onPressed: () => Navigator.of(context).pop(),
),
),
// 播放控制
if (_controller.value.isInitialized) _buildControls(),
],
),
),
),
);
}
}
/// 全屏横屏播放页面FullScreenVideoPage
class FullScreenVideoPage extends StatefulWidget {
final VideoPlayerController controller;
const FullScreenVideoPage({Key? key, required this.controller}) : super(key: key);
@override
State<FullScreenVideoPage> createState() => _FullScreenVideoPageState();
}
class _FullScreenVideoPageState extends State<FullScreenVideoPage> {
VideoPlayerController get _controller => widget.controller;
@override
void initState() {
super.initState();
// 进入横屏、沉浸式
SystemChrome.setPreferredOrientations([
DeviceOrientation.landscapeLeft,
DeviceOrientation.landscapeRight,
]);
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
}
@override
void dispose() {
// 恢复竖屏
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
DeviceOrientation.portraitDown,
]);
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: Center(
child: Stack(
children: [
// 全屏视频
if (_controller.value.isInitialized)
SizedBox.expand(child: VideoPlayer(_controller))
else
const Center(child: CircularProgressIndicator()),
// 简单控制:点击画面切换播放/暂停
GestureDetector(
onTap: () {
setState(() {
_controller.value.isPlaying
? _controller.pause()
: _controller.play();
});
},
),
// 返回按钮
Positioned(
top: 20,
left: 20,
child: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.white, size: 28),
onPressed: () => Navigator.of(context).pop(),
),
),
// 时间 & 进度条(简单版)
if (_controller.value.isInitialized)
Positioned(
bottom: 20,
left: 20,
right: 20,
child: Row(
children: [
Text(
'${_format(_controller.value.position)} / ${_format(_controller.value.duration)}',
style: const TextStyle(color: Colors.white),
),
const SizedBox(width: 12),
Expanded(
child: VideoProgressIndicator(
_controller,
allowScrubbing: true,
colors: VideoProgressColors(
playedColor: Colors.red,
bufferedColor: Colors.white54,
backgroundColor: Colors.white30,
),
),
),
],
),
),
],
),
),
);
}
String _format(Duration d) =>
'${d.inMinutes.remainder(60).toString().padLeft(2, '0')}:'
'${d.inSeconds.remainder(60).toString().padLeft(2, '0')}';
}