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

如何在Flutter中实现该页面滑动交互效果?

Flutter实现右侧左滑过半跳转页面效果

核心实现思路

  • 通过GestureDetector监听水平拖动事件,实时记录页面偏移量
  • 利用Transform.translate配合动画,实现页面跟随拖动的位移效果
  • 拖动结束时判断偏移量是否超过屏幕宽度的一半,决定跳转到新页面或回弹至原位置

完整代码示例

import 'package:flutter/material.dart';

class SwipeToNavigatePage extends StatefulWidget {
  const SwipeToNavigatePage({super.key});

  @override
  State<SwipeToNavigatePage> createState() => _SwipeToNavigatePageState();
}

class _SwipeToNavigatePageState extends State<SwipeToNavigatePage> with SingleTickerProviderStateMixin {
  late AnimationController _animationController;
  late Animation<double> _offsetAnimation;
  double _dragOffset = 0.0;
  late double _screenWidth;

  @override
  void initState() {
    super.initState();
    _animationController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 300),
    );
  }

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _screenWidth = MediaQuery.of(context).size.width;
  }

  @override
  void dispose() {
    _animationController.dispose();
    super.dispose();
  }

  void _handleDragUpdate(DragUpdateDetails details) {
    setState(() {
      // 限制仅向左拖动,偏移量范围控制在0到-屏幕宽度之间
      _dragOffset = details.localPosition.dx - _screenWidth;
      _dragOffset = _dragOffset.clamp(-_screenWidth, 0.0);
    });
  }

  void _handleDragEnd(DragEndDetails details) {
    if (_dragOffset.abs() > _screenWidth / 2) {
      // 滑出屏幕后跳转新页面
      _offsetAnimation = Tween<double>(begin: _dragOffset, end: -_screenWidth).animate(_animationController);
      _animationController.forward().then((_) {
        Navigator.push(context, MaterialPageRoute(builder: (context) => const NewPage()));
        _animationController.reset();
        setState(() => _dragOffset = 0.0);
      });
    } else {
      // 回弹至原位置
      _offsetAnimation = Tween<double>(begin: _dragOffset, end: 0.0).animate(_animationController);
      _animationController.forward().then((_) {
        _animationController.reset();
        setState(() => _dragOffset = 0.0);
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('可左滑跳转页面')),
      body: GestureDetector(
        onHorizontalDragUpdate: _handleDragUpdate,
        onHorizontalDragEnd: _handleDragEnd,
        child: AnimatedBuilder(
          animation: _offsetAnimation,
          builder: (context, child) {
            final currentOffset = _animationController.isAnimating ? _offsetAnimation.value : _dragOffset;
            return Transform.translate(
              offset: Offset(currentOffset, 0),
              child: child,
            );
          },
          child: Container(
            width: double.infinity,
            padding: const EdgeInsets.all(16),
            child: const Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text('从右侧向左拖动页面'),
                SizedBox(height: 20),
                Text('拖动超过屏幕一半后松开,即可跳转至新页面'),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

class NewPage extends StatelessWidget {
  const NewPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('新页面')),
      body: const Center(child: Text('这是跳转后的新页面')),
    );
  }
}

关键代码说明

  • 拖动监听:GestureDetector的onHorizontalDragUpdate实时更新页面偏移量,onHorizontalDragEnd处理拖动结束后的逻辑
  • 动画过渡:AnimationController配合Tween实现回弹和滑出的平滑动画,避免生硬的位移变化
  • 跳转判断:通过对比偏移量绝对值与屏幕宽度的一半,决定是触发页面跳转还是回弹

内容的提问来源于stack exchange,提问作者ThatKid

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 08:15:36