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

如何在Flutter中使用go_router关闭Drawer时平滑跳转至新页面

解决GoRouter跳转时Drawer关闭无动画的问题

问题根源在于:你每个页面都单独嵌套了Scaffold+Drawer,点击导航时先关闭Drawer再跳转页面,此时原页面的Scaffold会被直接销毁,Drawer的关闭动画自然被中断。

不用延迟的最优方案是把Scaffold和Drawer抽成全局外层容器,让路由切换的只是Scaffold的body内容,这样Drawer所在的容器不会被销毁,关闭动画能完整播放,同时完成页面切换。

修改后的完整代码如下:

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

void main() {
  runApp(const MainApp());
}

final _router = GoRouter(
  routes: <RouteBase>[
    ShellRoute(
      builder: (context, state, child) {
        // 外层统一渲染带Drawer的Scaffold
        return Scaffold(
          drawer: const AppDrawer(),
          appBar: AppBar(title: Text(state.location == '/' ? 'Home Screen' : 'News Screen')),
          body: child, // 子路由内容作为Scaffold的body
        );
      },
      routes: <RouteBase>[
        GoRoute(
          path: '/',
          builder: (context, state) => const HomeContent(),
        ),
        GoRoute(
          path: '/news',
          builder: (context, state) => const NewsContent(),
        ),
      ],
    ),
  ],
);

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerConfig: _router,
    );
  }
}

// 仅保留页面核心内容,不再嵌套Scaffold
class HomeContent extends StatelessWidget {
  const HomeContent({super.key});

  @override
  Widget build(BuildContext context) {
    return const Center(child: Text("Home"));
  }
}

// 仅保留页面核心内容,不再嵌套Scaffold
class NewsContent extends StatelessWidget {
  const NewsContent({super.key});

  @override
  Widget build(BuildContext context) {
    return const Center(child: Text("News"));
  }
}

class AppDrawer extends StatelessWidget {
  const AppDrawer({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Drawer(
      child: SafeArea(
        child: ListView(
          children: [
            ListTile(
              title: const Text('Home'),
              onTap: () {
                Navigator.pop(context); // 先关闭Drawer,动画正常执行
                // 避免重复跳转当前页面
                if (GoRouterState.of(context).location != '/') {
                  context.go('/'); // 仅替换Scaffold的body,外层容器不销毁
                }
              },
            ),
            ListTile(
              title: const Text('News'),
              onTap: () {
                Navigator.pop(context);
                if (GoRouterState.of(context).location != '/news') {
                  context.go('/news');
                }
              },
            ),
          ],
        ),
      ),
    );
  }
}

关键改动说明:

  • 用ShellRoute作为外层路由,统一管理带Drawer的Scaffold,子路由仅负责渲染页面核心内容。
  • 拆分原页面组件,去掉重复的Scaffold嵌套,让路由切换仅作用于Scaffold的body部分。
  • Drawer的导航逻辑中,先关闭Drawer(此时外层Scaffold仍存在,动画完整播放),再执行路由跳转,避免页面销毁打断动画。
  • 增加当前路由判断,防止重复跳转同一页面。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 15:32:10