Flutter 构建常用的 App 页面框架

简介: 详细讲解如何用 Flutter 构建一个底部导航的 App 页面框架
大多数 App 中都会有底部导航栏,通过底部导航栏切换实现不同页面之间的切换。在Flutter 中提供了 BottomNavigationBar组件实现底部导航。本篇介绍通过 BottomNavigationBar和 IndexedStack构建最为常见的App页面框架。

framework.jpg
最终实现的结果如上图所示,顶部共用一个导航栏,底部有四个图标导航,点击对应的图标跳转到对应的页面。

图标准备

本次例程需要4个图标,2种颜色,可以从 iconfont 中找到自己需要的图标下载不同的颜色使用。然后在 pubspec.yaml 中的 assets 指定素材所在目录。需要注意的是如果是 png 文件直接指定整个目录即可,但如果是 jpg 格式,则需要同时指定文件名及后缀。

BottomNavigationBar 简介

BottomNavigationBar的构造函数如下:

BottomNavigationBar({
    Key? key,
    required this.items,
    this.onTap,
    this.currentIndex = 0,
    this.elevation,
    this.type,
    Color? fixedColor,
    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,
  })

其中常用的属性为:

  • items:及对应的页面组件数组
  • currentIndex:默认显示第几个页面
  • type:组件类型,使用BottomNavigationBarType枚举,有fixed和shifting两种。fixed 是图标固定位置,而shifting的图标点击后会有一个漂移效果,可以实际试一下,一般用fixed比较多。
  • onTap:点击后的事件,一般用这个更新状态数据,以便更新页面。

其他属性用于控制样式的,可以根据实际需要设置图标大小,主题色,字体等参数。

构建项目页面结构

首先,新建四个业务页面,分别是 dynamic.dart,message.dart,category.dart和mine.dart,分别对应动态、消息、分类浏览和个人中心四个页面。目前这四个页面很简单,只是在页面中间依次显示“岛上码农”四个字。代码都是类似的,以dynamic为例:

import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Text('岛'),
      ),
    );
  }
}

注意的是这里的Scaffold没有AppBar了,这是因为在首页已经有了,如果再有AppBar就会出现两个,当然也可以把首页的去掉,每个页面使用自己的AppBar,这样可以每个页面的都不一样。。

其次,新建首页,用于管理四个业务页面,命名为 app.dart。app.dart 使用了 BottomNavigationBar 管理四个业务页面的切换。

import 'package:flutter/material.dart';
import 'dynamic.dart';
import 'message.dart';
import 'category.dart';
import 'mine.dart';

class AppHomePage extends StatefulWidget {
  AppHomePage({Key key}) : super(key: key);

  @override
  _AppHomePageState createState() => _AppHomePageState();
}

class _AppHomePageState extends State<AppHomePage> {
  int _index = 0;

  List<Widget> _homeWidgets = [
    DynamicPage(),
    MessagePage(),
    CategoryPage(),
    MinePage(),
  ];

  void _onBottomNagigationBarTapped(index) {
    setState(() {
      _index = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('岛上码农'),
      ),
      body: IndexedStack(
        index: _index,
        children: _homeWidgets,
      ),
      bottomNavigationBar: BottomNavigationBar(
        type: BottomNavigationBarType.fixed,
        currentIndex: _index,
        onTap: _onBottomNagigationBarTapped,
        items: [
          _getBottomNavItem(
              '动态', 'images/dynamic.png', 'images/dynamic-hover.png', 0),
          _getBottomNavItem(
              ' 消息', 'images/message.png', 'images/message-hover.png', 1),
          _getBottomNavItem(
              '分类浏览', 'images/category.png', 'images/category-hover.png', 2),
          _getBottomNavItem(
              '个人中心', 'images/mine.png', 'images/mine-hover.png', 3),
        ],
      ),
    );
  }

  BottomNavigationBarItem _getBottomNavItem(
      String title, String normalIcon, String pressedIcon, int index) {
    return BottomNavigationBarItem(
      icon: _index == index
          ? Image.asset(
              pressedIcon,
              width: 32,
              height: 28,
            )
          : Image.asset(
              normalIcon,
              width: 32,
              height: 28,
            ),
      label: title,
    );
  }
}

这里关键的地方有两个,一是使用的IndexedStack,这是一个管理页面显示层级的容器。使用index属性确定当前容器里那个页面在最顶上,容器里的页面通过children 属性设置,要求是一个Widget数组。因此,逻辑就是当BottomNavigationBar中的图标被点击后,对应点击事件会回调onTap属性指定的方法,将当前的点击索引值传递回调函数,因此可以利用这个方式控制IndexedStack的页面层级切换。

最后,使用了状态变量_index存储IndexedStatck当前显示页面的索引值,然后当BottomNavigationBar的图标点击事件发生后,在回调函数中使用 setState 更新状态变量_index 来刷新当前界面。

简化入口

main.dart是入口文件,应当做最基础的配置和全局初始化配置,而不应该有业务代码,因此可以简化为从main方法加载首页即可。通过这种方式可以让 main.dart 文件即为简洁。这也是在开发的时候需要注意的地方,将不相关的代码剥离,相关的代码聚合,即所谓的“高内聚,低耦合”原则。

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'App 框架',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: AppHomePage(),
    );
  }
}

代码复用

写代码的时候要注意复用,在这里将构建 BottomNavigationBar 元素抽离出了一个构建方法_getBottomNavItem,从而提高代码的复用性和维护性,也可以避免 Flutter 的组件构建的 build 方法中出现过多的元素和嵌套,影响代码的可读性。


欢迎关注个人公众号:岛上码农

相关文章
|
移动开发 前端开发 JavaScript
鸿蒙NEXT时代你所不知道的全平台跨端框架:CMP、Kuikly、Lynx、uni-app x等
本篇基于当前各大活跃的跨端框架的现状,对比当前它们的情况和未来的可能,帮助你在选择框架时更好理解它们的特点和差异。
1465 0
|
JSON 自然语言处理 数据格式
使用Tabs选项卡组件快速搭建鸿蒙APP框架
ArkUI提供了很多布局组件,其中Tabs选项卡组件可以用于快速搭建鸿蒙APP框架,本文通过案例研究Tabs构建鸿蒙原生应用框架的方法和步骤。
772 5
使用Tabs选项卡组件快速搭建鸿蒙APP框架
|
机器学习/深度学习 存储 人工智能
MNN-LLM App:在手机上离线运行大模型,阿里巴巴开源基于 MNN-LLM 框架开发的手机 AI 助手应用
MNN-LLM App 是阿里巴巴基于 MNN-LLM 框架开发的 Android 应用,支持多模态交互、多种主流模型选择、离线运行及性能优化。
19469 81
MNN-LLM App:在手机上离线运行大模型,阿里巴巴开源基于 MNN-LLM 框架开发的手机 AI 助手应用
|
小程序 安全 JavaScript
构建即时通讯APP内的小程序生态体系:从架构设计到技术实现-优雅草卓伊凡
构建即时通讯APP内的小程序生态体系:从架构设计到技术实现-优雅草卓伊凡
1372 1
构建即时通讯APP内的小程序生态体系:从架构设计到技术实现-优雅草卓伊凡
|
Java Shell Maven
【Azure Container App】构建Java应用镜像时候遇无法编译错误:ERROR [build 10/10] RUN ./mvnw.cmd dependency:go-offline -B -Dproduction package
在部署Java应用到Azure Container App时,构建镜像过程中出现错误:“./mvnw.cmd: No such file or directory”。尽管项目根目录包含mvnw和mvnw.cmd文件,但依然报错。问题出现在Dockerfile构建阶段执行`./mvnw dependency:go-offline`命令时,系统提示找不到可执行文件。经过排查,确认是mvnw文件内容异常所致。最终通过重新生成mvnw文件解决该问题,镜像成功构建。
799 1
《仿盒马》app开发技术分享-- 兑换订单列表框架(75)
上一节我们针对订单兑换的业务逻辑进行了完善,成功的在兑换物品之后修改了用户信息的修改,新增了积分消费的记录。这一节我们实现订单创建之后进入的列表展示页框架。
250 0
|
缓存
flutter3-wetrip跨平台自研仿携程app预约酒店系统模板
基于最新跨平台框架flutter3.x+dart3+getx+flutter_datepicker纯手写实战的一款仿去哪儿/携程旅游酒店预约客房app系统。
745 8
|
人工智能 自然语言处理 前端开发
从0到上线,CodeBuddy 如何帮我快速构建旅游 App?
本文详细介绍了AI代码助手CodeBuddy的功能与使用方法,并通过实战演示其在前端开发中的应用。文章首先讲解了CodeBuddy的安装步骤,以VS Code为例,引导用户快速上手。随后,通过构建一个旅游APP页面的实例,展示了CodeBuddy在生成代码、调整样式、修复问题等方面的能力。实战中涉及Craft模式交互、提示词优化、元素布局调整等内容,验证了插件的高效性与灵活性。尽管过程中遇到一些小问题,但整体效果令人满意。最后,文章鼓励开发者进一步探索CodeBuddy的潜力,为开发工作带来更多便利。
2236 0
|
开发工具 Android开发 iOS开发
零基础构建即时通讯开源项目OpenIM移动端-Flutter篇
OpenIM 为开发者提供开源即时通讯 SDK,作为 Twilio、Sendbird 等云服务的替代方案。借助 OpenIM,开发者可以构建安全可靠的即时通讯应用,如 WeChat、Zoom、Slack 等。 本仓库基于开源版 OpenIM SDK 开发,提供了一款基于 Flutter 的即时通讯应用。您可以使用此应用程序作为 OpenIM SDK 的参考实现。 开发环境 在开始开发之前,请确保您的系统已安装以下软件: 操作系统:macOS 14.6 或更高版本 Flutter:版本 3.24.5(根据官网步骤进行安装) Git:用于代码版本控制 同时,您需要确保已经部署了最
1548 10
|
应用服务中间件 Go Android开发
通过外部链接启动 Flutter App(详细介绍及示例)
本文介绍了通过外部链接启动 Flutter App 的两种方式:`firebase_dynamic_links` 和 `app_links`。前者由 Firebase 提供,支持生成分享链接并自动处理未安装应用时的跳转(如跳转到应用商店),但已于2025年8月停止服务;后者则需开发者自行处理未安装应用时的重定向逻辑。文中详细说明了两者的配置步骤、代码实现及注意事项,推荐使用 `app_links` 进行新项目开发。
1039 2

热门文章

最新文章