opt slide dismiss

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-08-27 15:22:19 +08:00
parent cf24f851e8
commit 077293854c
2 changed files with 87 additions and 79 deletions

View File

@@ -18,7 +18,6 @@ library;
import 'dart:async'; import 'dart:async';
import 'dart:math' as math; import 'dart:math' as math;
import 'dart:math' show max;
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart'; import 'package:flutter/gestures.dart';
@@ -782,6 +781,7 @@ class CustomScrollableState extends State<CustomScrollable>
bool? _lastCanDrag; bool? _lastCanDrag;
Axis? _lastAxisDirection; Axis? _lastAxisDirection;
late bool _isRTL = false;
Offset? _downPos; Offset? _downPos;
bool? _isSliding; bool? _isSliding;
@@ -893,7 +893,12 @@ class CustomScrollableState extends State<CustomScrollable>
ScrollHoldController? _hold; ScrollHoldController? _hold;
void _handleDragDown(DragDownDetails details) { void _handleDragDown(DragDownDetails details) {
if (details.localPosition.dx <= 30) { final dx = details.localPosition.dx;
const offset = 30;
final isLTR = dx <= offset;
final isRTL = dx >= _maxWidth - offset;
if (isLTR || isRTL) {
_isRTL = isRTL;
_downPos = details.localPosition; _downPos = details.localPosition;
return; return;
} }
@@ -915,19 +920,22 @@ class CustomScrollableState extends State<CustomScrollable>
_downPos = null; _downPos = null;
_isSliding = false; _isSliding = false;
} }
} else {
_downPos = null;
_isSliding = false;
} }
} else if (_isSliding == true) { } else if (_isSliding == true) {
if (localPosition.dx < 0) {
return;
}
_animController.value = _animController.value =
max(0, (localPosition.dx - _downPos!.dx)) / _maxWidth; (localPosition.dx - _downPos!.dx).abs() / _maxWidth;
} }
} }
void _onDismiss() { void _onDismiss() {
if (_isSliding == true) { if (_isSliding == true) {
if (_animController.value * _maxWidth + _downPos!.dx >= 100) { final dx = _downPos!.dx;
if (_animController.value * _maxWidth +
(_isRTL ? (_maxWidth - dx) : dx) >=
100) {
Get.back(); Get.back();
} else { } else {
_animController.reverse(); _animController.reverse();
@@ -1172,24 +1180,24 @@ class CustomScrollableState extends State<CustomScrollable>
); );
} }
return SlideTransition( return LayoutBuilder(
position: _anim, builder: (context, constraints) {
child: Material( _maxWidth = constraints.maxWidth;
color: widget.bgColor, return SlideTransition(
child: LayoutBuilder( position: _anim,
builder: (_, constrains) { child: Material(
_maxWidth = constrains.maxWidth; color: widget.bgColor,
return widget.header != null child: widget.header != null
? Column( ? Column(
children: [ children: [
widget.header!, widget.header!,
Expanded(child: result), Expanded(child: result),
], ],
) )
: result; : result,
}, ),
), );
), },
); );
} }

View File

@@ -13,7 +13,7 @@ abstract class CommonSlidePageState<T extends CommonSlidePage> extends State<T>
with TickerProviderStateMixin { with TickerProviderStateMixin {
Offset? downPos; Offset? downPos;
bool? isSliding; bool? isSliding;
late double maxWidth;
late bool _isRTL = false; late bool _isRTL = false;
late final bool enableSlide; late final bool enableSlide;
AnimationController? _animController; AnimationController? _animController;
@@ -47,9 +47,14 @@ abstract class CommonSlidePageState<T extends CommonSlidePage> extends State<T>
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
return enableSlide return enableSlide
? SlideTransition( ? LayoutBuilder(
position: _anim!, builder: (context, constraints) {
child: buildPage(theme), maxWidth = constraints.maxWidth;
return SlideTransition(
position: _anim!,
child: buildPage(theme),
);
},
) )
: buildPage(theme); : buildPage(theme);
} }
@@ -58,66 +63,61 @@ abstract class CommonSlidePageState<T extends CommonSlidePage> extends State<T>
Widget buildList(ThemeData theme) => throw UnimplementedError(); Widget buildList(ThemeData theme) => throw UnimplementedError();
Widget slideList(ThemeData theme) => LayoutBuilder( void onDismiss([_]) {
builder: (_, constrains) { if (isSliding == true) {
final maxWidth = constrains.maxWidth; final dx = downPos!.dx;
if (_animController!.value * maxWidth + (_isRTL ? (maxWidth - dx) : dx) >=
void onDismiss([_]) { 100) {
if (isSliding == true) { Get.back();
final dx = downPos!.dx; } else {
if (_animController!.value * maxWidth + _animController!.reverse();
(_isRTL ? (maxWidth - dx) : dx) >=
100) {
Get.back();
} else {
_animController!.reverse();
}
}
downPos = null;
isSliding = null;
} }
}
downPos = null;
isSliding = null;
}
void onPan(PositionedGestureDetails details) { void onPan(PositionedGestureDetails details) {
final localPosition = details.localPosition; final localPosition = details.localPosition;
if (isSliding == false) { if (isSliding == false) {
return; return;
} else if (isSliding == null) { } else if (isSliding == null) {
if (downPos != null) { if (downPos != null) {
Offset cumulativeDelta = localPosition - downPos!; Offset cumulativeDelta = localPosition - downPos!;
if (cumulativeDelta.dx.abs() >= cumulativeDelta.dy.abs()) { if (cumulativeDelta.dx.abs() >= cumulativeDelta.dy.abs()) {
downPos = localPosition; downPos = localPosition;
isSliding = true; isSliding = true;
} else { } else {
isSliding = false; isSliding = false;
}
} else {
isSliding = false;
}
} else if (isSliding == true) {
_animController!.value =
(details.localPosition.dx - downPos!.dx).abs() / maxWidth;
} }
} else {
isSliding = false;
} }
} else if (isSliding == true) {
_animController!.value =
(details.localPosition.dx - downPos!.dx).abs() / maxWidth;
}
}
return GestureDetector( void onPanDown(DragDownDetails details) {
onPanDown: (details) { final dx = details.localPosition.dx;
final dx = details.localPosition.dx; const offset = 30;
const offset = 30; final isLTR = dx <= offset;
final isLTR = dx <= offset; final isRTL = dx >= maxWidth - offset;
final isRTL = dx >= maxWidth - offset; if (isLTR || isRTL) {
if (isLTR || isRTL) { _isRTL = isRTL;
_isRTL = isRTL; downPos = details.localPosition;
downPos = details.localPosition; } else {
} else { isSliding = false;
isSliding = false; }
} }
},
onPanStart: onPan, Widget slideList(ThemeData theme) => GestureDetector(
onPanUpdate: onPan, onPanDown: onPanDown,
onPanCancel: onDismiss, onPanStart: onPan,
onPanEnd: onDismiss, onPanUpdate: onPan,
child: buildList(theme), onPanCancel: onDismiss,
); onPanEnd: onDismiss,
}, child: buildList(theme),
); );
} }