Flutter 构建常用的 App 页面框架

简介: 详细讲解如何用 Flutter 构建一个底部导航的 App 页面框架
大多数 App 中都会有底部导航栏,通过底部导航栏切换实现不同页面之间的切换。在Flutter 中提供了 BottomNavigationBar组件实现底部导航。本篇介绍通过 BottomNavigationBarIndexedStack构建最为常见的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枚举,有fixedshifting两种。fixed 是图标固定位置,而shifting的图标点击后会有一个漂移效果,可以实际试一下,一般用fixed比较多。
  • onTap:点击后的事件,一般用这个更新状态数据,以便更新页面。

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

构建项目页面结构

首先,新建四个业务页面,分别是 dynamic.dartmessage.dartcategory.dartmine.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.dartapp.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 方法中出现过多的元素和嵌套,影响代码的可读性。


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

相关文章
|
15天前
|
Dart Android开发 开发者
Flutter跨平台开发实战:构建高性能移动应用
【10月更文挑战第25天】随着移动设备种类的增加,开发者面临跨平台应用开发的挑战。Flutter作为Google推出的开源UI工具包,凭借其强大的跨平台能力和高效的开发效率,成为解决这一问题的新方案。本文将介绍Flutter的核心优势、实战技巧及性能优化方法,通过一个简单的待办事项列表应用示例,帮助读者快速上手Flutter,构建高性能的移动应用。
31 0
|
1月前
|
Dart 开发者
flutter:页面整合 (十)
本文档介绍了如何在 Flutter 应用中使用底部导航栏(`BottomNavigationBar`)和侧边栏(`Drawer`),包括简单的使用方法、属性配置、与按钮结合使用、使用图片作为图标、以及如何实现顶部导航。示例代码展示了如何创建包含多个页面的导航栏,并通过 `TabController` 控制器实现页面切换。同时,文档还提供了如何自定义导航栏样式和添加浮动操作按钮(`FloatingActionButton`)的方法。最后,整合了底部导航栏、侧边栏和顶部导航栏的完整示例代码,帮助开发者快速构建具有导航功能的 Flutter 应用界面。
|
1月前
|
前端开发 UED 开发者
uni-app:去除导航栏&跨域的问题&blobe查看图片&v-deep&页面操作 (五)
本文介绍了几个前端开发技巧:1) 如何通过设置 `navigationStyle` 为 `custom` 去除顶部导航;2) 解决跨域问题的方法,包括使用 `dotenv` 加载全局变量和配置 `devServer` 的代理;3) 使用 Blob 和 FileReader 查看图片;4) 利用 `v-deep` 深度作用选择器修改样式;5) 修改页面左上角返回按钮的行为。
|
1月前
|
监控 安全 Apache
构建安全的URL重定向策略:确保从Web到App平滑过渡的最佳实践
【10月更文挑战第2天】URL重定向是Web开发中常见的操作,它允许服务器根据请求的URL将用户重定向到另一个URL。然而,如果重定向过程没有得到妥善处理,可能会导致安全漏洞,如开放重定向攻击。因此,确保重定向过程的安全性至关重要。
66 0
|
3月前
|
Android开发 iOS开发 C#
Xamarin:用C#打造跨平台移动应用的终极利器——从零开始构建你的第一个iOS与Android通用App,体验前所未有的高效与便捷开发之旅
【8月更文挑战第31天】Xamarin 是一个强大的框架,允许开发者使用单一的 C# 代码库构建高性能的原生移动应用,支持 iOS、Android 和 Windows 平台。作为微软的一部分,Xamarin 充分利用了 .NET 框架的强大功能,提供了丰富的 API 和工具集,简化了跨平台移动应用开发。本文通过一个简单的示例应用介绍了如何使用 Xamarin.Forms 快速创建跨平台应用,包括设置开发环境、定义用户界面和实现按钮点击事件处理逻辑。这个示例展示了 Xamarin.Forms 的基本功能,帮助开发者提高开发效率并实现一致的用户体验。
149 0
|
3月前
|
开发者 监控 开发工具
如何将JSF应用送上云端?揭秘在Google Cloud Platform上部署JSF应用的神秘步骤
【8月更文挑战第31天】本文详细介绍如何在Google Cloud Platform (GCP) 上部署JavaServer Faces (JSF) 应用。首先,确保已准备好JSF应用并通过Maven构建WAR包。接着,使用Google Cloud SDK登录并配置GCP环境。然后,创建`app.yaml`文件以配置Google App Engine,并使用`gcloud app deploy`命令完成部署。最后,通过`gcloud app browse`访问应用,并利用GCP的监控和日志服务进行管理和故障排查。整个过程简单高效,帮助开发者轻松部署和管理JSF应用。
60 0
|
3月前
|
开发者 容器 Java
Azure云之旅:JSF应用的神秘部署指南,揭开云原生的新篇章!
【8月更文挑战第31天】本文探讨了如何在Azure上部署JavaServer Faces (JSF) 应用,充分发挥其界面构建能力和云平台优势,实现高效安全的Web应用。Azure提供的多种服务如App Service、Kubernetes Service (AKS) 和DevOps简化了部署流程,并支持应用全生命周期管理。文章详细介绍了使用Azure Spring Cloud和App Service部署JSF应用的具体步骤,帮助开发者更好地利用Azure的强大功能。无论是在微服务架构下还是传统环境中,Azure都能为JSF应用提供全面支持,助力开发者拓展技术视野与实践机会。
18 0
|
3月前
|
开发框架 API 开发者
Flutter表单控件深度解析:从基本构建到高级自定义,全方位打造既美观又实用的移动端数据输入体验,让应用交互更上一层楼
【8月更文挑战第31天】在构建美观且功能强大的移动应用时,表单是不可或缺的部分。Flutter 作为热门的跨平台开发框架,提供了丰富的表单控件和 API,使开发者能轻松创建高质量表单。本文通过问题解答形式,深入解读 Flutter 表单控件,并通过具体示例代码展示如何构建优秀的移动应用表单。涵盖创建基本表单、处理表单提交、自定义控件样式、焦点管理和异步验证等内容,适合各水平开发者学习和参考。
80 0
|
3月前
|
存储 XML Linux
深入理解操作系统:进程管理与调度策略探索安卓应用开发:从零开始构建你的第一个App
【8月更文挑战第28天】在数字世界里航行,操作系统是掌控一切的舵手。本文将带你领略操作系统的精妙设计,特别是进程管理和调度策略这两大核心领域。我们将从基础概念出发,逐步深入到复杂的实现机制,最后通过实际代码示例,揭示操作系统如何高效协调资源,确保多任务顺畅运行的秘密。准备好了吗?让我们启航,探索那些隐藏在日常电脑使用背后的奥秘。 【8月更文挑战第28天】在这个数字时代,拥有一款自己的移动应用程序不仅是技术的展示,也是实现创意和解决问题的一种方式。本文将引导初学者了解安卓开发的基础知识,通过一个简单的待办事项列表App项目,逐步介绍如何利用安卓开发工具和语言来创建、测试并发布一个基本的安卓应用
|
Dart API 开发工具
Flutter框架优缺点
Flutter框架优缺点
730 0

热门文章

最新文章