fix(recommend): 修正进度拖动与底栏联动
This commit is contained in:
1 parent
afe7a49ef0
commit
2765343340
9 files changed
+79
-107
No files matched your search
@@ -22,6 +22,7 @@ const double _progressHitHeight = 28;
|
||||
const double _pageHorizontal = 14;
|
||||
const double _railRight = 8;
|
||||
const double _railGap = 12;
|
||||
const double _bottomInfoInset = 20;
|
||||
const double _railBottomOffset = 60;
|
||||
const List<Shadow> _boostTextShadows = [
|
||||
Shadow(color: AppColors.shadow, blurRadius: 5, offset: Offset(0, 1)),
|
||||
@@ -141,7 +142,7 @@ class _HomeFeedOverlayState extends State<HomeFeedOverlay> {
|
||||
Positioned(
|
||||
left: _pageHorizontal,
|
||||
right: _railRight,
|
||||
bottom: 12,
|
||||
bottom: _bottomInfoInset,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
@@ -184,6 +185,7 @@ class _HomeFeedOverlayState extends State<HomeFeedOverlay> {
|
||||
void _endScrub() {
|
||||
final wasVisible = _wasVisibleBeforeScrub;
|
||||
if (_scrubbing) setState(() => _scrubbing = false);
|
||||
widget.onScrubVisibilityChanged?.call(false);
|
||||
widget.onScrubEnd?.call(wasVisible);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ class _FeedProgressBarState extends State<_FeedProgressBar> {
|
||||
double? _preview;
|
||||
Timer? _bufferTimer;
|
||||
bool _buffering = false;
|
||||
bool _dragging = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -61,6 +62,7 @@ class _FeedProgressBarState extends State<_FeedProgressBar> {
|
||||
_attachSource();
|
||||
}
|
||||
if (oldWidget.cancelScrubRequest != widget.cancelScrubRequest) {
|
||||
_dragging = false;
|
||||
_preview = null;
|
||||
}
|
||||
if (oldWidget.locked != widget.locked) {
|
||||
@@ -68,6 +70,7 @@ class _FeedProgressBarState extends State<_FeedProgressBar> {
|
||||
_bufferTimer = null;
|
||||
_buffering = false;
|
||||
if (widget.locked) {
|
||||
_dragging = false;
|
||||
_preview = null;
|
||||
} else {
|
||||
_syncBufferState(notify: false);
|
||||
@@ -88,7 +91,7 @@ class _FeedProgressBarState extends State<_FeedProgressBar> {
|
||||
builder: (context, constraints) {
|
||||
final width = constraints.maxWidth;
|
||||
final source = widget.controller;
|
||||
final scrubbing = _preview != null;
|
||||
final scrubbing = _dragging;
|
||||
final loading = !widget.locked && !scrubbing && _buffering;
|
||||
final track = widget.locked
|
||||
? _inactiveTrack()
|
||||
@@ -115,49 +118,41 @@ class _FeedProgressBarState extends State<_FeedProgressBar> {
|
||||
!loading &&
|
||||
(source?.value.isInitialized ?? false);
|
||||
final video = source?.value;
|
||||
final previewPosition = _preview == null || video == null
|
||||
final previewPosition = !_dragging || _preview == null || video == null
|
||||
? null
|
||||
: seekPositionForFraction(_preview!, video.duration);
|
||||
final showPreview = previewPosition != null;
|
||||
return GestureDetector(
|
||||
key: const Key('home-feed-progress'),
|
||||
return Listener(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onHorizontalDragStart: interactive
|
||||
? (details) {
|
||||
widget.onScrubStart?.call();
|
||||
_update(details.localPosition.dx / width);
|
||||
}
|
||||
: null,
|
||||
onHorizontalDragUpdate: interactive
|
||||
? (details) => _update(details.localPosition.dx / width)
|
||||
: null,
|
||||
onHorizontalDragEnd: interactive
|
||||
? (_) {
|
||||
widget.onScrubEnd?.call();
|
||||
_commit(_preview);
|
||||
}
|
||||
: null,
|
||||
onHorizontalDragCancel: interactive
|
||||
? () {
|
||||
widget.onScrubEnd?.call();
|
||||
_cancelPreview();
|
||||
}
|
||||
: null,
|
||||
child: Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
track,
|
||||
if (showPreview)
|
||||
Positioned(
|
||||
left: _timeBubbleLeft(width, _preview!),
|
||||
bottom: _lineCenterFromBottom + 16,
|
||||
child: _ScrubTimeBubble(
|
||||
key: const Key('scrub-preview-time-bubble'),
|
||||
position: previewPosition,
|
||||
duration: video!.duration,
|
||||
onPointerUp: (_) => _finishScrub(),
|
||||
onPointerCancel: (_) => _finishScrub(),
|
||||
child: GestureDetector(
|
||||
key: const Key('home-feed-progress'),
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onHorizontalDragStart: interactive
|
||||
? (details) => _startScrub(details.localPosition.dx / width)
|
||||
: null,
|
||||
onHorizontalDragUpdate: interactive
|
||||
? (details) => _update(details.localPosition.dx / width)
|
||||
: null,
|
||||
onHorizontalDragEnd: interactive ? (_) => _finishScrub() : null,
|
||||
onHorizontalDragCancel: interactive ? _finishScrub : null,
|
||||
child: Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
track,
|
||||
if (showPreview)
|
||||
Positioned(
|
||||
left: _timeBubbleLeft(width, _preview!),
|
||||
bottom: _lineCenterFromBottom + 16,
|
||||
child: _ScrubTimeBubble(
|
||||
key: const Key('scrub-preview-time-bubble'),
|
||||
position: previewPosition,
|
||||
duration: video!.duration,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -259,23 +254,32 @@ class _FeedProgressBarState extends State<_FeedProgressBar> {
|
||||
);
|
||||
}
|
||||
|
||||
void _startScrub(double fraction) {
|
||||
if (_dragging) return;
|
||||
setState(() {
|
||||
_dragging = true;
|
||||
_preview = fraction.clamp(0.0, 1.0).toDouble();
|
||||
});
|
||||
widget.onScrubStart?.call();
|
||||
}
|
||||
|
||||
void _update(double fraction) {
|
||||
if (!_dragging) return;
|
||||
setState(() => _preview = fraction.clamp(0.0, 1.0).toDouble());
|
||||
}
|
||||
|
||||
void _commit(double? fraction) {
|
||||
void _finishScrub() {
|
||||
if (!_dragging) return;
|
||||
final fraction = _preview;
|
||||
setState(() {
|
||||
_dragging = false;
|
||||
_preview = null;
|
||||
});
|
||||
widget.onScrubEnd?.call();
|
||||
if (widget.locked || fraction == null) return;
|
||||
final total = widget.controller?.value.duration.inMilliseconds ?? 0;
|
||||
if (total > 0) {
|
||||
widget.onSeek?.call(
|
||||
Duration(milliseconds: (total * fraction.clamp(0.0, 1.0)).round()),
|
||||
);
|
||||
}
|
||||
setState(() => _preview = null);
|
||||
}
|
||||
|
||||
void _cancelPreview() {
|
||||
setState(() => _preview = null);
|
||||
if (total <= 0) return;
|
||||
widget.onSeek?.call(Duration(milliseconds: (total * fraction).round()));
|
||||
}
|
||||
|
||||
Widget _track(double fraction, double width) {
|
||||
|
||||
Reference in new issue
Block a user