flutter_kinetra/lib/kt_widgets/kt_video_progress_bar.dart
2025-09-17 18:13:57 +08:00

137 lines
3.9 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:video_player/video_player.dart';
class CustomVideoProgressBar extends StatefulWidget {
final VideoPlayerController controller;
final double? width;
final bool canSlide;
const CustomVideoProgressBar({
super.key,
required this.controller,
this.width,
this.canSlide = true,
});
@override
State<CustomVideoProgressBar> createState() => _CustomVideoProgressBarState();
}
class _CustomVideoProgressBarState extends State<CustomVideoProgressBar> {
bool _isDragging = false;
double? _dragValue;
@override
void initState() {
super.initState();
widget.controller.addListener(_updateState);
}
@override
void dispose() {
widget.controller.removeListener(_updateState);
super.dispose();
}
void _updateState() {
if (!_isDragging) {
if (mounted) setState(() {});
}
}
String _formatDuration(Duration duration) {
final minutes = duration.inMinutes.remainder(60).toString().padLeft(2, '0');
final seconds = duration.inSeconds.remainder(60).toString().padLeft(2, '0');
return '$minutes:$seconds';
}
@override
Widget build(BuildContext context) {
final Duration duration = widget.controller.value.duration;
final Duration position = _isDragging
? Duration(milliseconds: _dragValue?.toInt() ?? 0)
: widget.controller.value.position;
return Column(
children: [
// 时间显示
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Text(
'${_formatDuration(position)}/',
style: TextStyle(color: Color(0xFFDFDFDF), fontSize: 10.sp),
),
Text(
_formatDuration(duration),
style: TextStyle(color: Color(0xFFDFDFDF), fontSize: 10.sp),
),
],
),
// 进度条
SizedBox(
width: widget.width ?? ScreenUtil().screenWidth - 30.w,
child: SliderTheme(
data: SliderTheme.of(context).copyWith(
trackHeight: 2.0.w,
trackShape: UniformTrackShape(),
thumbShape: RoundSliderThumbShape(enabledThumbRadius: 6.0),
),
child: Slider(
padding: EdgeInsets.zero,
min: 0,
max: duration.inMilliseconds.toDouble(),
value: position.inMilliseconds.toDouble().clamp(
0,
duration.inMilliseconds.toDouble(),
),
onChangeStart: (_) {
if (!widget.canSlide) return;
_isDragging = true;
},
onChangeEnd: (value) {
if (!widget.canSlide) return;
_isDragging = false;
widget.controller.seekTo(Duration(milliseconds: value.toInt()));
widget.controller.play();
_dragValue = null;
},
onChanged: (value) {
if (!widget.canSlide) return;
setState(() => _dragValue = value);
},
activeColor: Colors.white,
inactiveColor: Colors.white.withValues(alpha: .3),
),
),
),
],
);
}
}
// 自定义轨道形状,确保选中和未选中部分高度一致
class UniformTrackShape extends RoundedRectSliderTrackShape {
const UniformTrackShape();
@override
Rect getPreferredRect({
required RenderBox parentBox,
Offset offset = Offset.zero,
required SliderThemeData sliderTheme,
bool isEnabled = false,
bool isDiscrete = false,
}) {
final double? trackHeight = sliderTheme.trackHeight;
final double trackLeft = offset.dx;
final double trackTop =
offset.dy + (parentBox.size.height - trackHeight!) / 2;
final double trackWidth = parentBox.size.width;
return Rect.fromLTWH(trackLeft, trackTop, trackWidth, trackHeight);
}
}