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

Flutter中使用BottomNavigationBar时如何实现页面过渡动画

给BottomNavigationBar添加页面过渡动画

要给BottomNavigationBar的页面切换加上过渡动画,最直接的方案是用AnimatedSwitcher包裹页面区域,配合自定义动画逻辑实现。以下是具体实现步骤:

核心实现代码

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: 'BottomNav Animation',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const MainPage(),
    );
  }
}

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

  @override
  State<MainPage> createState() => _MainPageState();
}

class _MainPageState extends State<MainPage> {
  int _currentIndex = 0;
  bool _isForward = true; // 判断页面切换方向,用于自定义动画方向

  // 页面列表,替换成你的实际页面
  final List<Widget> _pages = const [
    HomePage(),
    ExplorePage(),
    ProfilePage(),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: AnimatedSwitcher(
        duration: const Duration(milliseconds: 300), // 动画时长
        transitionBuilder: (Widget child, Animation<double> animation) {
          // 自定义淡入+滑动动画,可替换成其他动画
          return FadeTransition(
            opacity: animation,
            child: SlideTransition(
              position: Tween<Offset>(
                // 根据切换方向决定滑入位置
                begin: _isForward ? const Offset(0.2, 0) : const Offset(-0.2, 0),
                end: Offset.zero,
              ).animate(animation),
              child: child,
            ),
          );
        },
        // 必须给页面设置唯一Key,让AnimatedSwitcher识别页面变化
        child: _pages[_currentIndex],
        key: ValueKey<int>(_currentIndex),
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        onTap: (index) {
          setState(() {
            _isForward = index > _currentIndex;
            _currentIndex = index;
          });
        },
        items: const [
          BottomNavigationBarItem(icon: Icon(Icons.home), label: '首页'),
          BottomNavigationBarItem(icon: Icon(Icons.explore), label: '发现'),
          BottomNavigationBarItem(icon: Icon(Icons.person), label: '我的'),
        ],
      ),
    );
  }
}

// 示例页面,可替换成你的实际页面
class HomePage extends StatefulWidget {
  const HomePage({super.key});

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin {
  // 开启状态保持,切换页面后保留页面状态
  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    super.build(context); // 必须调用super.build
    return const Center(child: Text('首页'));
  }
}

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

  @override
  Widget build(BuildContext context) {
    return const Center(child: Text('发现'));
  }
}

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

  @override
  Widget build(BuildContext context) {
    return const Center(child: Text('我的'));
  }
}

可选动画样式

如果不想用滑动+淡入,也可以换成其他动画:

  • 缩放动画
transitionBuilder: (Widget child, Animation<double> animation) {
  return ScaleTransition(
    scale: animation,
    child: child,
  );
},
  • 仅淡入淡出
transitionBuilder: (Widget child, Animation<double> animation) {
  return FadeTransition(opacity: animation, child: child);
},

注意事项

  1. 必须给每个页面设置唯一Key,ValueKey<int>(_currentIndex)是最简单的方式,确保AnimatedSwitcher能检测到页面变化
  2. 如果需要保留页面状态(比如输入框内容、滚动位置),给页面添加AutomaticKeepAliveClientMixin并实现wantKeepAlive返回true
  3. 动画时长可根据需求调整,300ms是比较符合用户习惯的时长

内容的提问来源于stack exchange,提问作者zubayer bin montasir

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 04:39:19