Flutter 构建一个常用的页面框架
作者:岛上码农 发布时间:2022-10-02 02:54:19
目录
图标准备
BottomNavigationBar 简介
构建项目页面结构
简化入口
代码复用
最终实现的结果如上图所示,顶部共用一个导航栏,底部有四个图标导航,点击对应的图标跳转到对应的页面。
图标准备
本次例程需要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 方法中出现过多的元素和嵌套,影响代码的可读性。
来源:https://juejin.cn/post/6963634035037831181


猜你喜欢
- java中this与super关键字的使用方法这几天看到类在继承时会用到this和super,这里就做了一点总结,与各位共同交流,有错误请各
- 刚实现了App内手机横/竖放置时,屏幕横/竖屏的切换。记录一下中间需要的关键信息和实现过程。开门见山的说,实现屏幕自动/手动旋转的方式有两种
- 本文实例讲述了C#显示文件夹下所有图片文件的方法。分享给大家供大家参考。具体实现方法如下:<%@ Page Language=&quo
- Runtime.getRuntime().exec 路径包含空格1. 现象java代码通过Runtime.getRuntime().exec
- 本文研究的主要是java fastdfs客户端使用实例的相关内容,具体实现如下。什么是FastDFS?FastDFS是用c语言编写的一款开源
- 在 Java SE 6 所提供的诸多新特性和改进中,值得一提的是为 Java 程序提供数据库访问机制的 JDBC 版本升级到了 4.0, 这
- ForkJoinTask就是ForkJoinPool里面的每一个任务。他主要有两个子类:RecursiveAction和RecursiveT
- 本文实例为大家分享了java实现砸金蛋抽奖的具体代码,供大家参考,具体内容如下代码如下需求:用户每一次砸金蛋,抽中一等奖的概率为2% 二等奖
- 详解Java读取Jar中资源文件及实现代码 &
- 由于公司平台访问人数逐渐增多,公司项目的数据库已经几次出现宕机现象。为减轻数据库压力,我上个月对公司项目做了下调整。把新闻板块提取出来单独一
- Mybatis是业界非常流行的持久层框架,轻量级、易用,在金融IT领域完全是领军地位,比Hibernate更受欢迎,优势非常多,也是非常值得
- 任何一个类都是Class类的实例对象,这个实例对象有三种表示方式第一种表示方式(任何一个类都有一个隐含的静态成员变量class):Class
- 最近碰到一个大转盘的业务,奖品可根据数据后台灵活设置中奖概率,看起来挺简单的业务功能,但实现起来对我这个毫无经验的人来说并不容易,后面又碰到
- 一、Redis分布式锁概念篇建议直接采用Redis的官方推荐的Redisson作为redis的分布式锁1.1、为什么要使用分布式锁 
- Android平台有三种网络接口可以使用,他们分别是:java.net.*(标准Java接口)、Org.apache接口和Android.n
- 在代码中进行命令行交互是一个很常见的场景, 特别是在一些CI CD 自动化流程中, 在这之前我们会使用 System.Diagnostics
- 1. matlab的lp2lp函数的作用去归一化 H(s) 的分母2. matlab的lp2lp函数的使用方法[z, p, k]=butta
- 简单的说下实现来电秀的大概原理流程:首先通过监听来电状态,通过拦截来电然后在窗口弹出一层系统级别的弹窗,这层弹窗即是来电秀。先来两张效果图:
- 概述在一个程序执行的过程中,各条语句的执行顺序对程序的结果是有直接影响的。也就是说,程序的流程对运行结果有直接的影响。所以,我们必须清楚每条
- 一提到委托,浮现在我们脑海中的大概是听的最多的就是类似C++的函数指针吧,呵呵,至少我的第一个反应是这样的。关于委托的定义和使用,已经有诸多