You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 20:22:31