feat: 增加侧滑事件
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
import 'dart:math';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'swipe/swipe_controller.dart';
|
||||
import 'swipe/swipe_config.dart';
|
||||
import 'package:kaer_with_panels/app/utils/kr_log_util.dart';
|
||||
|
||||
class HIEdgeSwipeDetector extends StatefulWidget {
|
||||
final Widget child;
|
||||
final double reservedEdgeWidth;
|
||||
final double detectionEdgeWidth;
|
||||
final double minSwipeDistance;
|
||||
final double minSwipeVelocity;
|
||||
final SwipeConfig? config;
|
||||
const HIEdgeSwipeDetector(
|
||||
{super.key,
|
||||
required this.child,
|
||||
this.reservedEdgeWidth = 0,
|
||||
this.detectionEdgeWidth = 20,
|
||||
this.minSwipeDistance = 20,
|
||||
this.minSwipeVelocity = 300,
|
||||
this.config});
|
||||
@override
|
||||
State<HIEdgeSwipeDetector> createState() => _HIEdgeSwipeDetectorState();
|
||||
}
|
||||
|
||||
class _HIEdgeSwipeDetectorState extends State<HIEdgeSwipeDetector> {
|
||||
Offset? _start;
|
||||
Offset? _last;
|
||||
DateTime? _startTime;
|
||||
final SwipeController _controller =
|
||||
Get.put(SwipeController(), permanent: true);
|
||||
bool _fromLeft = false;
|
||||
bool _fromRight = false;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
KRLogUtil.kr_d('HIEdgeSwipeDetector build');
|
||||
return Stack(
|
||||
fit: StackFit.expand,
|
||||
children: [
|
||||
widget.child,
|
||||
Positioned(
|
||||
left: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
width: widget.detectionEdgeWidth,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onHorizontalDragStart: (details) {
|
||||
_fromLeft = true;
|
||||
_fromRight = false;
|
||||
_start = details.globalPosition;
|
||||
_startTime = DateTime.now();
|
||||
KRLogUtil.kr_d('dragStart LEFT x=${details.globalPosition.dx}',
|
||||
tag: 'HIEdgeSwipeDetector');
|
||||
},
|
||||
onHorizontalDragUpdate: (details) {
|
||||
_last = details.globalPosition;
|
||||
KRLogUtil.kr_d('dragUpdate LEFT dx=${details.delta.dx}',
|
||||
tag: 'HIEdgeSwipeDetector');
|
||||
},
|
||||
onHorizontalDragEnd: (details) {
|
||||
if (_start == null || _startTime == null) return;
|
||||
final durationMs =
|
||||
DateTime.now().difference(_startTime!).inMilliseconds;
|
||||
final velocity = details.velocity.pixelsPerSecond.dx.abs();
|
||||
final distance = _last != null ? (_last!.dx - _start!.dx) : 0.0;
|
||||
final okByVelocity = velocity >= widget.minSwipeVelocity;
|
||||
final okByDistance = distance.abs() >= widget.minSwipeDistance;
|
||||
KRLogUtil.kr_d(
|
||||
'dragEnd LEFT vel=${details.velocity.pixelsPerSecond.dx} dur=$durationMs dist=$distance okV=$okByVelocity okD=$okByDistance',
|
||||
tag: 'HIEdgeSwipeDetector');
|
||||
if (!okByVelocity && !okByDistance) {
|
||||
_reset();
|
||||
return;
|
||||
}
|
||||
if (distance > 0) {
|
||||
final cfg = widget.config;
|
||||
if (cfg == null || !cfg.enableLeft) {
|
||||
_reset();
|
||||
return;
|
||||
}
|
||||
if (cfg.onLeft != null) {
|
||||
cfg.onLeft!();
|
||||
} else {
|
||||
Get.back();
|
||||
}
|
||||
}
|
||||
_reset();
|
||||
},
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
right: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
width: widget.detectionEdgeWidth,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onHorizontalDragStart: (details) {
|
||||
_fromLeft = false;
|
||||
_fromRight = true;
|
||||
_start = details.globalPosition;
|
||||
_startTime = DateTime.now();
|
||||
KRLogUtil.kr_d('dragStart RIGHT x=${details.globalPosition.dx}',
|
||||
tag: 'HIEdgeSwipeDetector');
|
||||
},
|
||||
onHorizontalDragUpdate: (details) {
|
||||
_last = details.globalPosition;
|
||||
KRLogUtil.kr_d('dragUpdate RIGHT dx=${details.delta.dx}',
|
||||
tag: 'HIEdgeSwipeDetector');
|
||||
},
|
||||
onHorizontalDragEnd: (details) {
|
||||
if (_start == null || _startTime == null) return;
|
||||
final durationMs =
|
||||
DateTime.now().difference(_startTime!).inMilliseconds;
|
||||
final velocity = details.velocity.pixelsPerSecond.dx.abs();
|
||||
final distance = _last != null ? (_last!.dx - _start!.dx) : 0.0;
|
||||
final okByVelocity = velocity >= widget.minSwipeVelocity;
|
||||
final okByDistance = distance.abs() >= widget.minSwipeDistance;
|
||||
KRLogUtil.kr_d(
|
||||
'dragEnd RIGHT vel=${details.velocity.pixelsPerSecond.dx} dur=$durationMs dist=$distance okV=$okByVelocity okD=$okByDistance',
|
||||
tag: 'HIEdgeSwipeDetector');
|
||||
if (!okByVelocity && !okByDistance) {
|
||||
_reset();
|
||||
return;
|
||||
}
|
||||
if (distance < 0) {
|
||||
final cfg = widget.config;
|
||||
if (cfg == null || !cfg.enableRight) {
|
||||
_reset();
|
||||
return;
|
||||
}
|
||||
if (cfg.onRight != null) {
|
||||
cfg.onRight!();
|
||||
} else {
|
||||
_controller.openRightMenu();
|
||||
}
|
||||
}
|
||||
_reset();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
void _reset() {
|
||||
_start = null;
|
||||
_last = null;
|
||||
_startTime = null;
|
||||
_fromLeft = false;
|
||||
_fromRight = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
import 'swipe_config.dart';
|
||||
|
||||
abstract class HasSwipeConfig {
|
||||
SwipeConfig get swipeConfig;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
class SwipeConfig {
|
||||
final bool enableLeft;
|
||||
final bool enableRight;
|
||||
final VoidCallback? onLeft;
|
||||
final VoidCallback? onRight;
|
||||
const SwipeConfig({this.enableLeft = false, this.enableRight = false, this.onLeft, this.onRight});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
import 'package:get/get.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:get/get_navigation/src/extension_navigation.dart';
|
||||
import 'package:kaer_with_panels/app/routes/app_pages.dart';
|
||||
import 'swipe_config.dart';
|
||||
import 'package:kaer_with_panels/app/utils/kr_log_util.dart';
|
||||
|
||||
class SwipeController extends GetxController {
|
||||
final Rxn<SwipeConfig> currentConfig = Rxn<SwipeConfig>();
|
||||
final RxInt currentPageIndex = 0.obs;
|
||||
final RxBool leftMenuOpen = false.obs;
|
||||
final RxBool rightMenuOpen = false.obs;
|
||||
void setConfig(SwipeConfig? config) {
|
||||
currentConfig.value = config;
|
||||
}
|
||||
|
||||
void setPageIndex(int index) {
|
||||
currentPageIndex.value = index;
|
||||
}
|
||||
|
||||
void closeMenus() {
|
||||
leftMenuOpen.value = false;
|
||||
rightMenuOpen.value = false;
|
||||
}
|
||||
|
||||
void openLeftMenu() {
|
||||
KRLogUtil.kr_d('openLeftMenu', tag: 'SwipeController');
|
||||
leftMenuOpen.value = true;
|
||||
Get.toNamed(Routes.HI_MENU);
|
||||
}
|
||||
|
||||
void openRightMenu() {
|
||||
KRLogUtil.kr_d('openRightMenu', tag: 'SwipeController');
|
||||
rightMenuOpen.value = true;
|
||||
Get.toNamed(Routes.KR_SETTING);
|
||||
}
|
||||
|
||||
void triggerLeft() {
|
||||
final cfg = currentConfig.value;
|
||||
if (cfg == null || !cfg.enableLeft) return;
|
||||
KRLogUtil.kr_d('call11 onLeft$cfg', tag: 'SwipeController');
|
||||
|
||||
if (cfg.onLeft != null) {
|
||||
KRLogUtil.kr_d('call onLeft', tag: 'SwipeController');
|
||||
cfg.onLeft!.call();
|
||||
return;
|
||||
}
|
||||
Get.back();
|
||||
}
|
||||
|
||||
void triggerRight() {
|
||||
final cfg = currentConfig.value;
|
||||
if (cfg == null || !cfg.enableRight) return;
|
||||
if (cfg.onRight != null) {
|
||||
KRLogUtil.kr_d('call onRight', tag: 'SwipeController');
|
||||
cfg.onRight!.call();
|
||||
return;
|
||||
}
|
||||
openRightMenu();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import '../hi_edge_swipe_detector.dart';
|
||||
import 'swipe_config.dart';
|
||||
import 'has_swipe_config.dart';
|
||||
import 'package:kaer_with_panels/app/utils/kr_log_util.dart';
|
||||
|
||||
class SwipeWrapper extends StatelessWidget {
|
||||
final Widget child;
|
||||
final SwipeConfig config;
|
||||
const SwipeWrapper({super.key, required this.child, required this.config});
|
||||
|
||||
static Widget detect(Widget Function() builder) {
|
||||
final w = builder();
|
||||
SwipeConfig effective = const SwipeConfig();
|
||||
if (w is HasSwipeConfig) {
|
||||
effective = (w as HasSwipeConfig).swipeConfig;
|
||||
} else if (GetPlatform.isIOS) {
|
||||
effective = SwipeConfig(enableLeft: true, onLeft: () => Get.back());
|
||||
}
|
||||
final enabled = effective.enableLeft ||
|
||||
effective.enableRight ||
|
||||
effective.onLeft != null ||
|
||||
effective.onRight != null;
|
||||
KRLogUtil.kr_d(
|
||||
'SwipeWrapper.detect enabled=$enabled left=${effective.enableLeft} right=${effective.enableRight}',
|
||||
tag: 'SwipeWrapper');
|
||||
if (!enabled) return w;
|
||||
return HIEdgeSwipeDetector(child: w, config: effective);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final effective = config;
|
||||
final enabled = effective.enableLeft ||
|
||||
effective.enableRight ||
|
||||
effective.onLeft != null ||
|
||||
effective.onRight != null;
|
||||
KRLogUtil.kr_d(
|
||||
'SwipeWrapper.build enabled=$enabled left=${effective.enableLeft} right=${effective.enableRight}',
|
||||
tag: 'SwipeWrapper');
|
||||
if (!enabled) return child;
|
||||
return HIEdgeSwipeDetector(child: child, config: effective);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user