简介

现在我们的 APP 上面都会在屏幕下方有一排的按钮,点击不同的按钮可以进入不同的界面。就是说在界面的底部会有一排的按钮导航。可看下面的图示。

完成图示

程序工程目录

梳理下实现步骤
我们需要实现这个底部菜单导航,就需要有底部菜单的那一排图标按钮。图标按钮是固定在一个工具栏 “bar” 上面。然后呢,需要分别需要有按钮对应的界面,就是说按钮有多少个,那么界面需要对应的有多少个。我们来一个清单列表:

按钮图标区域。由于展示的方式都是一样的,我们需要有一个单独的控件,循环出来就好。
工具栏区域。用于展示按钮图标,并且能固定在底部。
首页。用于将工具栏放入界面中,并且将按钮对应的界面作为它的子元素存放于其中。
不同的按钮对应的界面。在我们点击的图标按钮的时候,展示不同的界面。
我们底部的按钮是不会刷新的,界面会刷新,如何实现?

我们界面展示区域分为两块,一块展示底部的工具栏,一块展示页面。下面代码实现:

return new MaterialApp(
home: new Scaffold(
body: new Center(
child: _currentPage // 动态的展示我们当前的页面
),
bottomNavigationBar: bottomNavigationBar, // 底部工具栏
), theme: new ThemeData(
primarySwatch: Colors.blue, // 设置主题颜色
), );

具体实现
第一步:创建一个 flutter 工程
可以按照工程目录图中的结构,将对应的文件建好。

第二步:修改 main.dart。
main.dart 是我们程序的入口。就类似于 Java、C 中的 main() ,作为一个程序的入口。我们将 main.dart 作为程序的启动入口,就不做过多的操作,只是指定去加载我们的首页(index.dart)。

main.dart

import 'package:flutter/material.dart';
import 'package:flutter_demo/index/index.dart'; // 导入index.dart // 这里为入口函数
void main() => runApp(new MyApp()); class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
home: new Index(), // 指定去加载 Index页面。
);
}
}

第三步:创建 NavigationIconView。 
正如前面说的,我们底部的按钮区域展示的图标加上文字是固定格式,所以将这一部分抽取出来,作为一个公共的 class,方便界面程序维护。

navigation_icon_view.dart

import 'package:flutter/material.dart';

// 创建一个 Icon 展示控件
class NavigationIconView { // 创建两个属性,一个是 用来展示 icon, 一个是动画处理
final BottomNavigationBarItem item;
final AnimationController controller; // 类似于 java 中的构造方法
// 创建 NavigationIconView 需要传入三个参数, icon 图标,title 标题, TickerProvider
NavigationIconView({Widget icon, Widget title, TickerProvider vsync}):
item = new BottomNavigationBarItem(
icon: icon,
title: title,
),
controller = new AnimationController(
duration: kThemeAnimationDuration, // 设置动画持续的时间
vsync: vsync // 默认属性和参数
);
}

第四步:创建 Index 
这一步就比较重要了,因为我们需要在这个界面上面去布局,以及实现点击按钮图标之后,有事件触发。正因为我们需要有事件触发,所以创建一个带有状态的 Widget(StatefulWidget)。下面的代码注释给的很详细了,可以仔细看。

index.dart

import 'package:flutter/material.dart';
import 'package:flutter_demo/NoticePage/notice_page.dart';
import 'package:flutter_demo/home/home_page.dart';
import 'package:flutter_demo/idea/idea_page.dart';
import 'package:flutter_demo/market/market_page.dart';
import 'package:flutter_demo/my/my_page.dart'; import 'navigation_icon_view.dart'; // 如果是在同一个包的路径下,可以直接使用对应的文件名 // 创建一个 带有状态的 Widget Index
class Index extends StatefulWidget { // 固定的写法
@override
State<StatefulWidget> createState() => new _IndexState();
} // 要让主页面 Index 支持动效,要在它的定义中附加mixin类型的对象TickerProviderStateMixin
class _IndexState extends State<Index> with TickerProviderStateMixin{ int _currentIndex = ; // 当前界面的索引值
List<NavigationIconView> _navigationViews; // 底部图标按钮区域
List<StatefulWidget> _pageList; // 用来存放我们的图标对应的页面
StatefulWidget _currentPage; // 当前的显示页面 // 定义一个空的设置状态值的方法
void _rebuild() {
setState((){});
} @override
void initState() {
super.initState(); // 初始化导航图标
_navigationViews = <NavigationIconView>[
new NavigationIconView(icon: new Icon(Icons.assessment), title: new Text("首页"), vsync: this), // vsync 默认属性和参数
new NavigationIconView(icon: new Icon(Icons.all_inclusive), title: new Text("想法"), vsync: this),
new NavigationIconView(icon: new Icon(Icons.add_shopping_cart), title: new Text("市场"), vsync: this),
new NavigationIconView(icon: new Icon(Icons.add_alert), title: new Text("通知"), vsync: this),
new NavigationIconView(icon: new Icon(Icons.perm_identity), title: new Text("我的"), vsync: this),
]; // 给每一个按钮区域加上监听
for (NavigationIconView view in _navigationViews) {
view.controller.addListener(_rebuild);
} // 将我们 bottomBar 上面的按钮图标对应的页面存放起来,方便我们在点击的时候
_pageList = <StatefulWidget>[
new HomePage(),
new IdeaPage(),
new MarketPage(),
new NoticePage(),
new MyPage()
];
_currentPage = _pageList[_currentIndex];
} @override
Widget build(BuildContext context) { // 声明定义一个 底部导航的工具栏
final BottomNavigationBar bottomNavigationBar = new BottomNavigationBar(
items: _navigationViews
.map((NavigationIconView navigationIconView) => navigationIconView.item)
.toList(), // 添加 icon 按钮
currentIndex: _currentIndex, // 当前点击的索引值
type: BottomNavigationBarType.fixed, // 设置底部导航工具栏的类型:fixed 固定
onTap: (int index){ // 添加点击事件
setState((){ // 点击之后,需要触发的逻辑事件
_navigationViews[_currentIndex].controller.reverse();
_currentIndex = index;
_navigationViews[_currentIndex].controller.forward();
_currentPage = _pageList[_currentIndex];
});
},
); return new MaterialApp(
home: new Scaffold(
body: new Center(
child: _currentPage // 动态的展示我们当前的页面
),
bottomNavigationBar: bottomNavigationBar, // 底部工具栏
), theme: new ThemeData(
primarySwatch: Colors.blue, // 设置主题颜色
), );
} }

第四步:创建页面 
前面的步骤都是在搭建我们的基础,现在是做展示界面。由于不同的界面,对应的源码都是和下面的是一样的,只是 class 的名字不一样,就都可以使用同样的模版复制过去就有可以了。

home_page.dart

import 'package:flutter/material.dart';

class HomePage extends StatefulWidget{
@override
State<StatefulWidget> createState() => new _HomePageState();
} class _HomePageState extends State<HomePage> { @override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: new Text('首页'),
actions: <Widget>[
new Container()
],
),
body: new Center(
child: null,
),
),
);
}
}
idea_page.dart
import 'package:flutter/material.dart';

class IdeaPage extends StatefulWidget{
@override
State<StatefulWidget> createState() => new _IdeaPageState();
}
class _IdeaPageState extends State<IdeaPage> { @override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: new Text('想法'),
actions: <Widget>[
new Container()
],
),
body: new Center(
child: null,
),
),
);
}
}

market_page.dart

import 'package:flutter/material.dart';
class MarketPage extends StatefulWidget{
@override
State<StatefulWidget> createState() => new _MarketPageState();
}
class _MarketPageState extends State<MarketPage> {
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: new Text('市场'),
// 后面的省略
// ......
)
),
);
} }

Flutter学习之制作底部菜单导航的更多相关文章

  1. 转-TabHost组件(一)(实现底部菜单导航)

    http://www.cnblogs.com/lichenwei/p/3974009.html 什么是TabHost? TabHost组件的主要功能是可以进行应用程序分类管理,例如:在用户使用wind ...

  2. 转-TabHost组件(二)(实现底部菜单导航)

    http://www.cnblogs.com/lichenwei/p/3975095.html 上面文章<安卓开发复习笔记——TabHost组件(一)(实现底部菜单导航)>中提到了利用自定 ...

  3. 安卓开发笔记——TabHost组件(二)(实现底部菜单导航)

    上面文章<安卓开发复习笔记——TabHost组件(一)(实现底部菜单导航)>中提到了利用自定义View(ImageView+TextView)来设置一个底部菜单的样式 这边再补充一种更为灵 ...

  4. 安卓开发笔记——TabHost组件(一)(实现底部菜单导航)

    什么是TabHost? TabHost组件的主要功能是可以进行应用程序分类管理,例如:在用户使用windows操作系统的时候,经常见到如图所示的图形界面.     TabHost选项卡,说到这个组件, ...

  5. Android底部菜单的实现

    前言:以前制作菜单使用TabHost,但是android 3.0以上就被废弃了,google已经不建议使这个类了.ActionBar也是菜单,不过在头部,算是导航了 ===本文就介绍怎么制作底部菜单= ...

  6. 转-Fragment+FragmentTabHost组件(实现新浪微博底部菜单)

    http://www.cnblogs.com/lichenwei/p/3985121.html 记得之前写过2篇关于底部菜单的实现,由于使用的是过时的TabHost类,虽然一样可以实现我们想要的效果, ...

  7. 安卓开发笔记——Fragment+FragmentTabHost组件(实现新浪微博底部菜单)

    记得之前写过2篇关于底部菜单的实现,由于使用的是过时的TabHost类,虽然一样可以实现我们想要的效果,但作为学习,还是需要来了解下这个新引入类FragmentTabHost 之前2篇文章的链接: 安 ...

  8. Jetpack Compose学习(7)——MD样式架构组件Scaffold及导航底部菜单

    Jetpack Compose学习(7)--MD样式架构组件Scaffold及导航底部菜单 | Stars-One的杂货小窝 Compose给我们提供了一个Material Design样式的首页组件 ...

  9. 【Flutter学习】基本组件之BottomNavigationBar底部导航栏

    一,概述 BottomNavigationBar即是底部导航栏控件,显示在页面底部的设计控件,用于在试图切换,底部导航栏包含多个标签.图标或者两者搭配的形式,简而言之提供了顶级视图之间的快速导航. 二 ...

随机推荐

  1. AngularJS入门之数据绑定

    本篇我们看一下AngularJS中的数据绑定.虽然我们直到这篇才提到数据绑定,但事实上在前面几篇中我们已经非常熟练的运用AngularJS的数据绑定功能了! ngBind(ng-bind)/ {{ e ...

  2. hive算法报错..

    hive普通语句查询报错.. 查到以下设定项,,附加在语句前执行成功.. 但是有可能没有真正的执行.. 试到最后使用标红的三行附加在语法前执行成功 set hive.execution.engine= ...

  3. 剑指offer四十五之扑克牌顺子(序列是否连续)

    一.题目 LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决 ...

  4. EJB3 事物

    在ejb3中事物分为两种类型:容器管理的事物(CMT).Bean管理的事物(BMT) 1.容器管理的事物(CTN) 是EJB默认的事物管理方式,即以对应的方法起始和结束来由EJB容器确定事务的始末边界 ...

  5. Python的Django框架中forms表单类的使用方法详解

    用户表单是Web端的一项基本功能,大而全的Django框架中自然带有现成的基础form对象,本文就Python的Django框架中forms表单类的使用方法详解. Form表单的功能 自动生成HTML ...

  6. 全局描述符表(GDT)——《x86汇编语言:从实模式到保护模式》读书笔记09

    在进入保护模式之前,我们先要学习一些基础知识.今天我们看一下全局描述符表(Global Descriptor Table, 简称GDT). 同实模式一样,在保护模式下,对内存的访问仍然使用段地址加偏移 ...

  7. 自学C Primer Plus时还没想明白的问题

    2016年11月24日 1. 计算机中两个浮点数怎样进行加法运算.2. 为什么计算机在计算时存在损失精度的可能3. 无符号数和有符号数的运算是怎样的4. printf中使用格式控制符的截断问题,比如% ...

  8. ANTLR4权威指南 - 第6章 尝试一些实际中的语法

    第6章 尝试一些实际中的语法 在前一章,我们学习了通用词法结构和语法结构,并学习了如何用ANTLR的语法来表述这些结构.现在,是时候把我们学到的这些用来构建一些现实世界中的语法了.我们的主要目标是,怎 ...

  9. [转载]常见的移动端H5页面开发遇到的坑和解决办法

    转过来,平时看看.虽然还有很多问题至今无解.比如:华为麒麟950的P8和meta打开我们的应用首页经常偶发白屏.!! 1.安卓浏览器看背景图片,有些设备会模糊. 用同等比例的图片在PC机上很清楚,但是 ...

  10. win7下使用IIS服务器及自定义服务器端包含模块(SSI)步骤

    配置完过段时间就容易忘记,特此记录. 1.开启IIS服务器. 默认没有安装,需要先安装. 打开控制面板–> 打开“程序和功能”–> 左侧选择“启用或关闭windows功能”–> 找到 ...