Flutter 构建一个常用的页面框架

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

图标准备

本次例程需要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 就会出现两个。

其次,新建首页,用于管理四个业务页面,命名为 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 方法中出现过多的元素和嵌套,影响代码的可读性。

以上就是Flutter 构建一个常用的页面框架的详细内容,更多关于Flutter 构建页面框架的资料请关注我们其它相关文章!

(0)

相关推荐

  • Flutter学习之构建、布局及绘制三部曲

    前言 学习Fullter也有些时间了,写过不少demo,对一些常用的widget使用也比较熟练,但是总觉得对Flutter的框架没有一个大致的了解,碰到有些细节的地方又没有文档可以查询,例如在写UI时总不知道为什么container添加了child就变小了:widget中key的作用,虽然官方有解释但是凭空来讲的话有点难理解.所以觉得深入一点的了解Flutter框架还是很有必要的. 构建 初次构建 flutter的入口main方法直接调用了runApp(Widget app)方法,app参数就是

  • Flutter路由框架Fluro使用简介

    在Flutter应用开发过程中,除了使用Flutter官方提供的路由外,还可以使用一些第三方路由框架来实现页面管理和导航,如Fluro.Frouter等. Fluro作为一款优秀的Flutter企业级路由框架,Fluro的使用比官方提供的路由框架要复杂一些,但是却非常适合中大型项目.因为它具有层次分明.条理化.方便扩展和便于整体管理路由等优点. 使用Fluro之前需要先在pubspec.yaml文件中添加Fluro依赖,如下所示. dependencies: fluro: "^1.5.1&quo

  • Flutter 使用Navigator进行局部跳转页面的方法

    Navigator组件使用的频率不是很高,但在一些场景下非常适用,比如局部表单多页填写.底部导航一直存在,每个tab各自导航场景. Navigator 是管理路由的控件,通常情况下直接使用Navigator.of(context)的方法来跳转页面,之所以可以直接使用Navigator.of(context)是因为在WidgetsApp中使用了此控件,应用程序的根控件通常是MaterialApp,MaterialApp包含WidgetsApp,所以可以直接使用Navigator的相关属性. Nav

  • Flutter实现页面切换后保持原页面状态的3种方法

    前言: 在Flutter应用中,导航栏切换页面后默认情况下会丢失原页面状态,即每次进入页面时都会重新初始化状态,如果在initState中打印日志,会发现每次进入时都会输出,显然这样增加了额外的开销,并且带来了不好的用户体验. 在正文之前,先看一些常见的App导航,以喜马拉雅FM为例: 它拥有一个固定的底部导航以及首页的顶部导航,可以看到不管是点击底部导航切换页面还是在首页左右侧滑切换页面,之前的页面状态都是始终维持的,下面就具体介绍下如何在flutter中实现类似喜马拉雅的导航效果 第一步:实

  • Flutter 网络请求框架封装详解

     Flutter 请求网络的三种方式 flutter 请求网络的方式有三种,分别是 Dart 原生的网络请求 HttpClient.第三方网络请求 http以及 Flutter 中的 Dio.我们可以比较一下这三种网络请求方式,然后封装为我们方便请求网络的工具类. Dart 原生的网络请求 HttpClient 实现 Dart 获取网络数据的请求,一般我们需要以下几个步骤: step 1: 原生的网络请求时不需要修改 pubspec.yaml 文件的,我们只需要在使用的地方引入所需包就可以了 i

  • Flutter页面传值的几种方式

    今天来聊聊Flutter页面传值的几种方式: InheritWidget Notification Eventbus (当前Flutter版本:2.0.4) InheritWidget 如果看过Provider的源码的同学都知道,Provider跨组件传值的原理就是根据系统提供的InheritWidget实现的,让我们来看一下这个组件. InheritWidget是一个抽象类,我们写一个保存用户信息的类UserInfoInheritWidget继承于InheritWidget: class Us

  • flutter编写精美的登录页面

    本文实例为大家分享了flutter编写精美的登录页面的具体代码,供大家参考,具体内容如下 先看效果图; 源代码已上传到github 我们先看一下页面 , 首先这个页面,我们并没有用到AppBar,当然也就没有自带返回功能. 然后下面有个Login的文字以及一条横线. 屏幕中上方是填写帐号以及密码的2个输入框,密码输入框有隐藏和显示密码的按钮. 下方是登录按钮 以及其他登录方式. 看一下主体布局: return Scaffold( body: Form( key: _formKey, child:

  • Flutter 构建一个常用的页面框架

    最终实现的结果如上图所示,顶部共用一个导航栏,底部有四个图标导航,点击对应的图标跳转到对应的页面. 图标准备 本次例程需要4个图标,2种颜色,可以从 iconfont 中找到自己需要的图标下载不同的颜色使用.然后在 pubspec.yaml 中的 assets 指定素材所在目录.需要注意的是如果是 png 文件直接指定整个目录即可,但如果是 jpg 格式,则需要同时指定文件名及后缀. BottomNavigationBar 简介 BottomNavigationBar的构造函数如下: Botto

  • 30分钟用Node.js构建一个API服务器的步骤详解

    Node.js 对初学者来说可能是令人望而却步的,其灵活的结构和缺乏严格的规范使它看起来很复杂. 本教程是 Node.js,Express 框架和 MongoDB 的快速指南,重点介绍基本的 REST 路由和基本的数据库交互.你将构建一个简单的 API 框架模版,然后可以将其用作任何应用. 本教程适用于:你应该对 REST API 和 CRUD 操作有基本的了解,还有基本的 JavaScript 知识.我用的是 ES6(主要是箭头函数),但并不是很复杂. 在本教程中,我们将为创建一个网络笔记应用

  • ios开发Flutter构建todo list应用

    目录 正文 基础 Flutter 应用脚手架 创建 TodoItem 展示 Dialog 去添加列表项 列表项添加状态 正文 今天,我们将使用 Flutter 构建一个动态的 todo list 的应用. 开发完成的效果如下: 我们直接进入正题. 基础 Flutter 应用脚手架 # create new project flutter create flutter_todo_app # navigate to project cd flutter_todo_app # run flutter

  • Flutter 开发一个登录页面

    业务逻辑 为了演示登录跳转,在分类浏览先做了一个简单的按钮,点击跳转到登录页面.实际的 App 中,通常会是触发某些需要登录才能查看的操作后再跳转到登录界面. 布局分析 界面如上图所示,从界面上看,整体内容区域是居中的,内容的布局是一个简单的列式布局,包括了顶部的一个 Logo(通常是 App图标),再往下是两个文本输入框,最后是登录按钮.整体布局比较简单,使用 Center 下嵌一个Column 进行列布局即可. 图片圆形裁剪 在 Flutter 中实行图片圆形裁剪有两个方式,一是使用外层的容

  • python 常用的异步框架汇总整理

    目录 正文开始 1. Tornado 2. Aiohttp 3.Sanic 4. FastAPI 5. Ruia 总结 参考资料 正文开始 asyncio 是 Python 3.4版本引入的标准库,直接内置了对异步IO的支持. asyncio 在单线程内部维护了 EventLoop 队列,然后把需要执行异步IO的任务添加到 EventLoop 队列中,至于任务的完成通过类似回调的逻辑是实现后续的任务.如果你有 JavaScript的基础那么理解python的 asyncio 很简单,关键字.语法

  • 从0快速搭建一个实用的MVVM框架(超详细)

    目录 前言 基于MVVM进行快速开发,上手即用.(重构已完成,正在编写SampleApp) 如何集成 1.继承BaseApplication 2.创建ViewModel扩展函数 3.引入一键生成代码插件(可选) 框架结构 mvvm Activity封装 Fragment封装 Adapter封装 LiveData封装 Navigation封装 ViewModel封装 辅助类封装 管理类封装 mvvm_navigation mvvm_network 结合Jetpack,构建快速开发的MVVM框架.

  • Vue 2.0+Vue-router构建一个简单的单页应用(附源码)

    一.介绍 vue.js 是 目前 最火的前端框架,vue.js 兼具 angular.js 和 react.js 的优点,并剔除它们的缺点,并且提供了很多的周边配套工具 如vue-router .vue-resource .vuex等等 ,通过他们我们可以很轻松的构建一个大型单页应用. 目前Vue版本为:Vue2.0 官网地址:http://vuejs.org.cn/ 查看API文档:https://vuefe.cn/v2/api/ 对比其他框架:http://vuejs.org.cn/guid

  • Flutter 封装一个 Banner 轮播图效果的实例代码

    实际业务开发中,首页一般都会存在一个轮播图. 在 Flutter 中,如何开发一个轮播? 了解需求 首先,我们在开发一个功能的时候要了解这个功能的需求,那一个轮播需要有什么功能? 1. 可以自定义高度和一些属性 2. 展示图片 3. 自动翻页播放 4. 点击事件 5. 指示器 6. 人为拖动的时候关闭自动播放 其中「人为拖动的时候关闭自动播放」是比较难的,我们后续会说,那先一个一个功能来实现. 自定义高度和一些属性 这里主要是做一些前期的工作,如果我们的 Banner 要开源让别人来使用,那我们

  • Java构建对象常用3种方法解析

    前言 当我们面对具有大量可选成员变量的 Java 类时,创建这些对象的最佳方法是什么?通常有三种方法: 伸缩构造函数,JavaBean模式和构建器模式. 构造函数 UserInfo userInfo1 = new UserInfo("felord.cn", 28); UserInfo xxxxxx = new UserInfo("felord.cn", "xxxxxx", 28); UserInfo xxxxxx1 = new UserInfo(

  • vue.js样式布局Flutter业务开发常用技巧

    阴影样式中flutter和css对应关系 UI给出的css样式 width: 75px; height: 75px; background-color: rgba(255, 255, 255, 1); border-radius: 4px; box-shadow: 0px 0.5px 5px 0px rgba(0, 0, 0, 0.08); flutter样式布局 Container( constraints: BoxConstraints.tightFor(width: 75, height:

随机推荐