Flutter现有左滑拖拽代码如何添加右滑拖拽支持?
Flutter 实现抽屉双向左右拖拽功能
现有代码已支持从左向右拖拽打开抽屉(显示底层"TEST"组件),现在要添加反向操作:支持从右向左拖拽关闭抽屉(顶部白色组件向左滑动归位)。只需修改_onDragStart方法的触发逻辑即可实现,以下是完整方案:
修改核心方法
更新_onDragStart,扩展拖拽触发的区域条件,允许在抽屉关闭时从右侧边缘拖拽打开,以及抽屉打开时从左侧边缘拖拽关闭:
void _onDragStart(DragStartDetails details) { final screenWidth = MediaQuery.of(context).size.width; // 抽屉关闭时:左右两侧边缘都可拖拽打开 final isDragOpen = _animationController.isDismissed && (details.globalPosition.dx < minDragStartEdge || details.globalPosition.dx > screenWidth - minDragStartEdge); // 抽屉打开时:左右两侧边缘都可拖拽关闭 final isDragClose = _animationController.isCompleted && (details.globalPosition.dx < maxDragStartEdge || details.globalPosition.dx > screenWidth - maxDragStartEdge); _canBeDragged = isDragOpen || isDragClose; }
修改后的完整代码
import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({super.key}); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, brightness: Brightness.dark, ), home: const MyHome(), ); } } class MyHome extends StatefulWidget { const MyHome(); @override State<StatefulWidget> createState() => _MyHome(); } class _MyHome extends State<MyHome> with SingleTickerProviderStateMixin { late AnimationController _animationController; final double maxSlide = 225.0; final double minDragStartEdge = 150.0; final double maxDragStartEdge = 250.0; bool _canBeDragged = true; @override void initState() { _animationController = AnimationController( vsync: this, duration: const Duration(milliseconds: 250), ); super.initState(); } @override Widget build(BuildContext context) { return Scaffold( body: GestureDetector( onHorizontalDragStart: _onDragStart, onHorizontalDragUpdate: _onDragUpdate, onHorizontalDragEnd: _onDragEnd, child: AnimatedBuilder( animation: _animationController, builder: (BuildContext context, _) { final slide = maxSlide * _animationController.value; final scale = 1 - (_animationController.value / 0.20); return Stack( children: [ const Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( 'TEST', style: TextStyle(color: Colors.white, fontSize: 32.0), ), ], ), Transform( transform: Matrix4.identity() ..translate(slide) ..scale(scale), alignment: Alignment.centerLeft, child: SizedBox.expand( child: Container( color: Colors.white, margin: const EdgeInsets.only(top:50), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Row( children: [ IconButton( onPressed: () {}, icon: const Icon(Icons.menu)), const Text('Appbar'), ], ), const Text( 'TEXT', style: TextStyle(color: Colors.black, fontSize: 32.0), ), ], ), ), ), ), ], ); }, ), ), ); } void _onDragStart(DragStartDetails details) { final screenWidth = MediaQuery.of(context).size.width; // 抽屉关闭状态:支持左右两侧边缘拖拽打开 final isDragOpen = _animationController.isDismissed && (details.globalPosition.dx < minDragStartEdge || details.globalPosition.dx > screenWidth - minDragStartEdge); // 抽屉打开状态:支持左右两侧边缘拖拽关闭 final isDragClose = _animationController.isCompleted && (details.globalPosition.dx < maxDragStartEdge || details.globalPosition.dx > screenWidth - maxDragStartEdge); _canBeDragged = isDragOpen || isDragClose; } void _onDragUpdate(DragUpdateDetails details) { if (_canBeDragged) { final delta = details.primaryDelta! / maxSlide; _animationController.value += delta; } } void _onDragEnd(DragEndDetails details) { if (_animationController.isDismissed || _animationController.isCompleted) { return; } if (details.velocity.pixelsPerSecond.dx.abs() >= 165.0) { final visualVelocity = details.velocity.pixelsPerSecond.dx / MediaQuery.of(context).size.width; _animationController.fling(velocity: visualVelocity); } else if (_animationController.value < 0.5) { closeDrawer(); } else { openDrawer(); } } void openDrawer() { _animationController.forward(); } void closeDrawer() { _animationController.reverse(); } }
功能说明
- 抽屉关闭时:点击屏幕左侧150px范围内或右侧150px范围内,均可向右拖拽打开抽屉
- 抽屉打开时:点击屏幕左侧250px范围内或右侧250px范围内,均可向左拖拽关闭抽屉
- 保留原有的拖拽速度判断和自动归位逻辑,确保滑动流畅自然
内容的提问来源于stack exchange,提问作者DolDurma
相关产品推荐
相关产品推荐

