Flutter 初识:导航控件

路由与导航

Navigator

Navigator 用于管理应用程序的路由,通过堆栈结构来实现页面的进出。它支持页面的推入(push)和弹出(pop)操作,允许在应用中进行复杂的导航模式。

核心方法
  • Navigator.push: 将新页面推入导航堆栈。
  • Navigator.pop: 从导航堆栈中弹出当前页面。
  • Navigator.pushReplacement: 替换当前页面,并将新页面推入导航堆栈。
  • Navigator.pushNamed: 使用命名路由推入新页面。
  • Navigator.popUntil: 弹出导航堆栈中的页面直到满足特定条件。
  • Navigator.pushAndRemoveUntil: 推入新页面并移除所有先前的页面,直到满足特定条件。
  • Navigator.maybePop: 尝试从导航堆栈中弹出当前页面,如果没有更多页面可以弹出,则返回false。
属性
  • initialRoute: 应用启动时的初始路由。
  • onGenerateRoute: 动态生成路由的回调函数。
  • onUnknownRoute: 当无法找到匹配路由时调用的回调函数。
示例
基本导航示例
Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => SecondPage()),
);

Navigator.pop(context);
替换当前页面并推入新页面
Navigator.pushReplacement(
  context,
  MaterialPageRoute(builder: (context) => SecondPage()),
);
使用命名路由

定义命名路由:

void main() {
  runApp(MaterialApp(
    initialRoute: '/',
    routes: {
      '/': (context) => FirstPage(),
      '/second': (context) => SecondPage(),
    },
  ));
}

使用命名路由导航:

Navigator.pushNamed(context, '/second');
动态生成路由
void main() {
  runApp(MaterialApp(
    onGenerateRoute: (settings) {
      if (settings.name == '/second') {
        return MaterialPageRoute(
          builder: (context) => SecondPage(),
        );
      }
      // Define other routes here
      assert(false, 'Need to implement ${settings.name}');
      return null;
    },
  ));
}
额外的导航功能

推入新页面并移除所有先前的页面,直到满足特定条件

Navigator.pushAndRemoveUntil(
  context,
  MaterialPageRoute(builder: (context) => SecondPage()),
  ModalRoute.withName('/'),
);

尝试从导航堆栈中弹出当前页面

bool popped = await Navigator.maybePop(context);
if (!popped) {
  // Handle the case where there are no more pages to pop
}
完整示例代码
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      initialRoute: '/',
      routes: {
        '/': (context) => FirstPage(),
        '/second': (context) => SecondPage(),
        '/third': (context) => ThirdPage(),
      },
    );
  }
}

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("First Page")),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () {
                Navigator.push(
                  context,
                  MaterialPageRoute(builder: (context) => SecondPage()),
                );
              },
              child: Text('Push to Second Page'),
            ),
            ElevatedButton(
              onPressed: () {
                Navigator.pushReplacement(
                  context,
                  MaterialPageRoute(builder: (context) => SecondPage()),
                );
              },
              child: Text('PushReplace to Second Page'),
            ),
            ElevatedButton(
              onPressed: () {
                Navigator.pushNamed(context, '/third');
              },
              child: Text('Go to Third Page with Named Route'),
            ),
          ],
        ),
      ),
    );
  }
}

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Second Page")),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () {
                Navigator.pop(context, 'Data from Second Page');
              },
              child: Text('Pop and Return Data'),
            ),
            ElevatedButton(
              onPressed: () {
                Navigator.popUntil(context, ModalRoute.withName('/'));
              },
              child: Text('Pop Until First Page'),
            ),
            ElevatedButton(
              onPressed: () {
                Navigator.pushAndRemoveUntil(
                  context,
                  MaterialPageRoute(builder: (context) => ThirdPage()),
                  ModalRoute.withName('/'),
                );
              },
              child: Text('Push and Remove Until First Page'),
            ),
          ],
        ),
      ),
    );
  }
}

class ThirdPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Third Page")),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            ElevatedButton(
              onPressed: () {
                Navigator.pop(context);
              },
              child: Text('Back to Previous Page'),
            ),
            ElevatedButton(
              onPressed: () async {
                bool popped = await Navigator.maybePop(context);
                if (!popped) {
                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(content: Text('No more pages to pop')),
                  );
                }
              },
              child: Text('Maybe Pop'),
            ),
          ],
        ),
      ),
    );
  }
}

 
 

MaterialPageRoute

MaterialPageRoute 是一个材料设计风格的页面路由,用于在安卓平台上提供一致的导航体验。它继承自PageRoute,并且实现了TransitionRoute用于处理页面切换时的过渡动画。

属性
  • builder: 构建路由页面的回调函数。
  • settings: 路由的配置信息,如名称、参数等。
  • maintainState: 是否在页面离开视图但未完全移除时保持状态。
  • fullscreenDialog: 是否将页面展示为全屏对话框。
示例
Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => SecondPage(),
    settings: RouteSettings(name: '/second'),
  ),
);

在SecondPage中接收传递的参数:

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final RouteSettings settings = ModalRoute.of(context)!.settings;
    final String? data = settings.arguments as String?;

    return Scaffold(
      appBar: AppBar(title: Text("Second Page")),
      body: Center(child: Text(data ?? 'No data')),
    );
  }
}

 
 

CupertinoPageRoute

CupertinoPageRoute 是一个iOS风格的页面路由,用于在iOS平台上提供一致的导航体验。它同样继承自PageRoute,并实现了TransitionRoute用于处理页面切换时的过渡动画。

属性
  • builder: 构建路由页面的回调函数。
  • settings: 路由的配置信息,如名称、参数等。
  • maintainState: 是否在页面离开视图但未完全移除时保持状态。
  • fullscreenDialog: 是否将页面展示为全屏对话框。
示例
Navigator.push(
  context,
  CupertinoPageRoute(
    builder: (context) => SecondPage(),
    settings: RouteSettings(name: '/second'),
  ),
);

在SecondPage中接收传递的参数:

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final RouteSettings settings = ModalRoute.of(context)!.settings;
    final String? data = settings.arguments as String?;

    return CupertinoPageScaffold(
      navigationBar: CupertinoNavigationBar(
        middle: Text("Second Page"),
      ),
      child: Center(child: Text(data ?? 'No data')),
    );
  }
}

 
 

应用栏与底部导航

AppBar

AppBar 是顶部应用栏,通常用于显示标题、导航按钮等。

属性解析
AppBar({
    super.key,
    this.leading,
    this.automaticallyImplyLeading = true,
    this.title,
    this.actions,
    this.flexibleSpace,
    this.bottom,
    this.elevation,
    this.scrolledUnderElevation,
    this.notificationPredicate = defaultScrollNotificationPredicate,
    this.shadowColor,
    this.surfaceTintColor,
    this.shape,
    this.backgroundColor,
    this.foregroundColor,
    this.iconTheme,
    this.actionsIconTheme,
    this.primary = true,
    this.centerTitle,
    this.excludeHeaderSemantics = false,
    this.titleSpacing,
    this.toolbarOpacity = 1.0,
    this.bottomOpacity = 1.0,
    this.toolbarHeight,
    this.leadingWidth,
    this.toolbarTextStyle,
    this.titleTextStyle,
    this.systemOverlayStyle,
    this.forceMaterialTransparency = false,
    this.clipBehavior,
  })
  • key:用于标识控件的唯一值。
  • leading:可选参数,类型为 Widget,表示前导控件,通常是导航图标。
  • automaticallyImplyLeading:可选参数,类型为 bool,默认为 true,是否自动根据路由生成前导控件。
  • title:可选参数,类型为 Widget,表示标题控件。
  • actions:可选参数,类型为 List,表示操作控件列表,通常是一些图标按钮。
  • flexibleSpace:可选参数,类型为 Widget,表示灵活空间控件。
  • bottom:可选参数,类型为 PreferredSizeWidget,表示底部控件,通常是 TabBar。
  • elevation:可选参数,类型为 double,表示阴影高度。
  • scrolledUnderElevation:可选参数,类型为 double,表示滑动时的阴影高度。
  • notificationPredicate:可选参数,类型为 ScrollNotificationPredicate,表示通知谓词。
  • shadowColor:可选参数,类型为 Color,表示阴影颜色。
  • surfaceTintColor:可选参数,类型为 Color,表示表面颜色。
  • shape:可选参数,类型为 ShapeBorder,表示形状。
  • backgroundColor:可选参数,类型为 Color,表示背景颜色。
  • foregroundColor:可选参数,类型为 Color,表示前景颜色。
  • iconTheme:可选参数,类型为 IconThemeData,表示图标主题。
  • actionsIconTheme:可选参数,类型为 IconThemeData,表示操作图标主题。
  • primary:可选参数,类型为 bool,默认为 true,表示是否为主 AppBar。
  • centerTitle:可选参数,类型为 bool,表示标题是否居中。
  • excludeHeaderSemantics:可选参数,类型为 bool,表示是否排除头部语义。
  • titleSpacing:可选参数,类型为 double,表示标题间距。
  • toolbarOpacity:可选参数,类型为 double,表示工具栏不透明度,默认为 1.0。
  • bottomOpacity:可选参数,类型为 double,表示底部控件不透明度,默认为 1.0。
  • toolbarHeight:可选参数,类型为 double,表示工具栏高度。
  • leadingWidth:可选参数,类型为 double,表示前导控件宽度。
  • toolbarTextStyle:可选参数,类型为 TextStyle,表示工具栏文字样式。
  • titleTextStyle:可选参数,类型为 TextStyle,表示标题文字样式。
  • systemOverlayStyle:可选参数,类型为 SystemUiOverlayStyle,表示系统覆盖层样式。
  • forceMaterialTransparency:可选参数,类型为 bool,表示是否强制材料透明度。
  • clipBehavior:可选参数,类型为 Clip,表示剪切行为。
示例
class ExamplePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(
          leading: IconButton(
            icon: Icon(Icons.menu),
            onPressed: () {
              // handle menu button press
            },
          ),
          title: Text('AppBar Example'),
          actions: <Widget>[
            IconButton(
              icon: Icon(Icons.search),
              onPressed: () {
                // handle search button press
              },
            ),
            IconButton(
              icon: Icon(Icons.more_vert),
              onPressed: () {
                // handle more button press
              },
            ),
          ],
          flexibleSpace: Container(
            decoration: BoxDecoration(
              gradient: LinearGradient(
                colors: [Colors.blue, Colors.purple],
                begin: Alignment.topLeft,
                end: Alignment.bottomRight,
              ),
            ),
          ),
          bottom: PreferredSize(
            preferredSize: Size.fromHeight(50.0),
            child: Container(
              color: Colors.orange,
              height: 50.0,
              child: Center(child: Text('Bottom Widget')),
            ),
          ),
          elevation: 4.0,
          backgroundColor: Colors.red,
          foregroundColor: Colors.white,
          centerTitle: true,
        ),
        body: Center(child: Text('Hello, world!')),
      ),
    );
  }
}

在这里插入图片描述
 
 

BottomNavigationBar

BottomNavigationBar 是底部导航栏,用于在底部展示多个导航项。

属性解析
BottomNavigationBar({
  super.key,
  required this.items,                   // 必需参数,导航栏项列表
  this.onTap,                            // 点击事件回调
  this.currentIndex = 0,                 // 当前选中的索引
  this.elevation,                        // 阴影高度
  this.type,                             // 导航栏类型
  Color? fixedColor,                     // 固定颜色(已废弃,请使用 selectedItemColor)
  this.backgroundColor,                  // 背景颜色
  this.iconSize = 24.0,                  // 图标大小
  Color? selectedItemColor,              // 选中项颜色
  this.unselectedItemColor,              // 未选中项颜色
  this.selectedIconTheme,                // 选中图标主题
  this.unselectedIconTheme,              // 未选中图标主题
  this.selectedFontSize = 14.0,          // 选中标签字体大小
  this.unselectedFontSize = 12.0,        // 未选中标签字体大小
  this.selectedLabelStyle,               // 选中标签样式
  this.unselectedLabelStyle,             // 未选中标签样式
  this.showSelectedLabels,               // 是否显示选中标签
  this.showUnselectedLabels,             // 是否显示未选中标签
  this.mouseCursor,                      // 鼠标指针样式
  this.enableFeedback,                   // 是否启用反馈
  this.landscapeLayout,                  // 横向布局
  this.useLegacyColorScheme = true,      // 是否使用旧颜色方案
});
  • key:用于标识控件的唯一值。
  • items:必需参数,类型为 List,表示导航栏项列表。
  • onTap:可选参数,类型为 ValueChanged?,点击事件回调,当导航栏项被点击时调用。
  • currentIndex:可选参数,类型为 int,默认为 0,表示当前选中的索引。
  • elevation:可选参数,类型为 double?,表示阴影高度。
  • type:可选参数,类型为 BottomNavigationBarType?,表示导航栏类型,可以是 fixed 或 shifting。
  • backgroundColor:可选参数,类型为 Color?,表示背景颜色。
  • iconSize:可选参数,类型为 double,表示图标大小,默认为 24.0。
  • selectedItemColor:可选参数,类型为 Color?,表示选中项颜色。
  • unselectedItemColor:可选参数,类型为 Color?,表示未选中项颜色。
  • selectedIconTheme:可选参数,类型为 IconThemeData?,表示选中图标主题。
  • unselectedIconTheme:可选参数,类型为 IconThemeData?,表示未选中图标主题。
  • selectedFontSize:可选参数,类型为 double,表示选中标签字体大小,默认为 14.0。
  • unselectedFontSize:可选参数,类型为 double,表示未选中标签字体大小,默认为 12.0。
  • selectedLabelStyle:可选参数,类型为 TextStyle?,表示选中标签样式。
  • unselectedLabelStyle:可选参数,类型为 TextStyle?,表示未选中标签样式。
  • showSelectedLabels:可选参数,类型为 bool?,表示是否显示选中标签。
  • showUnselectedLabels:可选参数,类型为 bool?,表示是否显示未选中标签。
  • mouseCursor:可选参数,类型为 MouseCursor?,表示鼠标指针样式。
  • enableFeedback:可选参数,类型为 bool?,表示是否启用反馈。
  • landscapeLayout:可选参数,类型为 BottomNavigationBarLandscapeLayout?,表示横向布局方式。
  • useLegacyColorScheme:可选参数,类型为 bool,表示是否使用旧颜色方案,默认为 true。
示例
class BottomPage extends StatefulWidget {
  @override
  _BottomPageState createState() => _BottomPageState();
}

class _BottomPageState extends State<BottomPage> {
  int _selectedIndex = 0;

  static const List<Widget> _widgetOptions = <Widget>[
    Text('Home Page',
        style: TextStyle(fontSize: 35, fontWeight: FontWeight.bold)),
    Text('Search Page',
        style: TextStyle(fontSize: 35, fontWeight: FontWeight.bold)),
    Text('Profile Page',
        style: TextStyle(fontSize: 35, fontWeight: FontWeight.bold)),
  ];

  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(title: Text('BottomNavigationBar Example')),
        body: Center(
          child: _widgetOptions.elementAt(_selectedIndex),
        ),
        bottomNavigationBar: BottomNavigationBar(
          items: const <BottomNavigationBarItem>[
            BottomNavigationBarItem(
              icon: Icon(Icons.home),
              label: 'Home',
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.search),
              label: 'Search',
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.person),
              label: 'Profile',
            ),
          ],
          currentIndex: _selectedIndex,
          selectedItemColor: Colors.amber[800],
          onTap: _onItemTapped,
        ),
      ),
    );
  }
}

在这里插入图片描述
 
 

Drawer

Drawer 是抽屉导航,一般从屏幕左侧滑入,包含导航菜单项。

属性解析
const Drawer({
  super.key,
  this.backgroundColor,      // 抽屉的背景颜色
  this.elevation,            // 阴影高度
  this.shadowColor,          // 阴影颜色
  this.surfaceTintColor,     // 表面颜色
  this.shape,                // 形状
  this.width,                // 宽度
  this.child,                // 子控件
  this.semanticLabel,        // 语义标签
  this.clipBehavior,         // 剪切行为
});
  • key:用于标识控件的唯一值。
  • backgroundColor:可选参数,类型为 Color?,表示抽屉的背景颜色。
  • elevation:可选参数,类型为 double?,表示阴影高度。
  • shadowColor:可选参数,类型为 Color?,表示阴影颜色。
  • surfaceTintColor:可选参数,类型为 Color?,表示表面颜色。
  • shape:可选参数,类型为 ShapeBorder?,表示形状。
  • width:可选参数,类型为 double?,表示宽度。
  • child:可选参数,类型为 Widget?,表示子控件。
  • semanticLabel:可选参数,类型为 String?,表示语义标签。
  • clipBehavior:可选参数,类型为 Clip?,表示剪切行为。
示例
class ExamplePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(
          title: Text('Drawer Example'),
        ),
        body: Center(
          child: Text(
              'Swipe from the left or click on the menu icon to open the drawer.'),
        ),
        drawer: Drawer(
          backgroundColor: Colors.white,
          elevation: 16.0,
          child: ListView(
            padding: EdgeInsets.zero,
            children: <Widget>[
              DrawerHeader(
                decoration: BoxDecoration(
                  color: Colors.blue,
                ),
                child: Text(
                  'Drawer Header',
                  style: TextStyle(
                    color: Colors.white,
                    fontSize: 24,
                  ),
                ),
              ),
              ListTile(
                leading: Icon(Icons.home),
                title: Text('Home'),
                onTap: () {
                  // Handle the tap event here
                  Navigator.pop(context);
                },
              ),
              ListTile(
                leading: Icon(Icons.settings),
                title: Text('Settings'),
                onTap: () {
                  // Handle the tap event here
                  Navigator.pop(context);
                },
              ),
              ListTile(
                leading: Icon(Icons.contacts),
                title: Text('Contacts'),
                onTap: () {
                  // Handle the tap event here
                  Navigator.pop(context);
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}

在这里插入图片描述

 
 

示例

class FirstPage extends StatefulWidget {
  @override
  _FirstPageState createState() => _FirstPageState();
}

class _FirstPageState extends State<FirstPage> {
  int _selectedIndex = 0;

  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("First Page"),
      ),
      drawer: Drawer(
        child: ListView(
          padding: EdgeInsets.zero,
          children: <Widget>[
            DrawerHeader(
              decoration: BoxDecoration(
                color: Colors.blue,
              ),
              child: Text(
                'Drawer Header',
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 24,
                ),
              ),
            ),
            ListTile(
              leading: Icon(Icons.message),
              title: Text('Messages'),
              onTap: () {
                // Handle navigation
              },
            ),
            ListTile(
              leading: Icon(Icons.account_circle),
              title: Text('Profile'),
              onTap: () {
                // Handle navigation
              },
            ),
            ListTile(
              leading: Icon(Icons.settings),
              title: Text('Settings'),
              onTap: () {
                // Handle navigation
              },
            ),
          ],
        ),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(
                  builder: (context) =>
                      SecondPage(data: 'Hello from First Page')),
            );
          },
          child: Text('Go to Second Page'),
        ),
      ),
      bottomNavigationBar: BottomNavigationBar(
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: 'Home',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.business),
            label: 'Business',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.school),
            label: 'School',
          ),
        ],
        currentIndex: _selectedIndex,
        selectedItemColor: Colors.amber[800],
        onTap: _onItemTapped,
      ),
    );
  }
}

class SecondPage extends StatelessWidget {
  final String data;

  SecondPage({required this.data});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Second Page")),
      body: Center(child: Text(data)),
    );
  }
}
  • 27
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值