服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Android - Flutter质感设计之底部导航

Flutter质感设计之底部导航

2022-07-22 10:52何小有 Android

这篇文章主要为大家详细介绍了Flutter质感设计之底部导航的相关代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

BottomNavigationBar即底部导航栏控件。显示在应用底部的质感设计控件,用于在少量视图中切换。底部导航栏包含多个以标签、图标或两者搭配的形式显示在项目底部的项目,提供了应用程序的顶级视图之间的快速导航。对于较大的屏幕,侧面导航可能更好。

创建navigation_icon_view.dart文件,定义一个NavigationIconView类,用于管理BottomNavigationBarItem(底部导航栏项目)控件的样式、行为与动画。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import 'package:flutter/material.dart';
// 创建类,导航图标视图
class NavigationIconView {
 // 导航图标视图的构造函数
 NavigationIconView({
  // 控件参数,传递图标
  Widget icon,
  // 控件参数,传递标题
  Widget title,
  // 控件参数,传递颜色
  Color color,
  /*
   * Ticker提供者
   * 由类实现的接口,可以提供Ticker对象
   *  Ticker对象:每个动画帧调用它的回调一次
   */
  TickerProvider vsync,
 }):_icon = icon, //接收传递的图标
  // 接收传递的颜色
  _color = color,
  // 创建底部导航栏项目
  item = new BottomNavigationBarItem(
   // 项目的图标
   icon: icon,
   // 项目的标题
   title: title
  ),
  // 创建动画控制器
  controller = new AnimationController(
   // 动画持续的时间长度:默认情况下主题更改动画的持续时间
   duration: kThemeAnimationDuration,
   // 垂直同步
   vsync: vsync,
  ) {
   // 创建曲线动画
   _animation = new CurvedAnimation(
    // 应用曲线动画的动画
    parent: controller,
    /*
     * 正向使用的曲线:
     * 从0.5
     * 到1.0结束
     * 应用的曲线:快速启动并缓和到最终位置的曲线
     */
    curve: new Interval(0.5, 1.0, curve: Curves.fastOutSlowIn),
   );
  }
 // 类成员,存储图标
 final Widget _icon;
 // 类成员,存储颜色
 final Color _color;
 // 类成员,底部导航栏项目
 final BottomNavigationBarItem item;
 // 类成员,动画控制器
 final AnimationController controller;
 // 类成员,曲线动画
 CurvedAnimation _animation;
 /*
  * 类函数,过渡转换
  * BottomNavigationBarType:定义底部导航栏的布局和行为
  * BuildContext:处理控件树中的控件
  */
 FadeTransition transition(BottomNavigationBarType type, BuildContext context) {
  // 局部变量,存储图标颜色
  Color iconColor;
  // 如果底部导航栏的位置和大小在点击时会变大
  if (type == BottomNavigationBarType.shifting) {
   // 存储颜色作为图标颜色
   iconColor = _color;
  } else {
   /*
    * 保存质感设计主题的颜色和排版值:
    * 使用ThemeData来配置主题控件
    * 使用Theme.of获取当前主题
    */
   final ThemeData themeData = Theme.of(context);
   /*
    * 如果程序整体主题的亮度很高(需要深色文本颜色才能实现可读的对比度)
    * 就返回程序主要部分的背景颜色作为图标颜色
    * 否则返回控件的前景颜色作为图标颜色
    */
   iconColor = themeData.brightness == Brightness.light
    ? themeData.primaryColor
    : themeData.accentColor;
  }
  // 返回值,创建不透明度转换
  return new FadeTransition(
   // 控制子控件不透明度的动画
   opacity: _animation,
   // 子控件:创建滑动转换过渡
   child: new SlideTransition(
    /*
     * 控制子控件位置的动画
     * 开始值和结束值之间的线性插值<以尺寸的分数表示的偏移量>
     *  (1.0,0.0)表示Size的右上角
     *  (0.0,1.0)表示Size的左下角
     */
    position: new Tween<FractionalOffset>(
     // 此变量在动画开头的值
     begin: const FractionalOffset(0.0, 0.02),
     // 此变量在动画结尾处的值:左上角
     end: FractionalOffset.topLeft,
    ).animate(_animation), // 返回给定动画,该动画接受由此对象确定的值
    // 子控件:创建控制子控件的颜色,不透明度和大小的图标主题
    child: new IconTheme(
     // 用于子控件中图标的颜色,不透明度和大小
     data: new IconThemeData(
      // 图标的默认颜色
      color: iconColor,
      // 图标的默认大小
      size: 120.0,
     ),
     // 子控件
     child: _icon,
    )
   )
  );
 }
}

再创建main.dart文件。类CustomIcon创建一个容器控件,作为一个自定义的图标使用。同时使用质感设计的弹出菜单控件切换底部导航栏的行为和样式。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
import 'package:flutter/material.dart';
import 'navigation_icon_view.dart';
// 创建类,自定义图标,继承StatelessWidget(无状态的控件)
class CustomIcon extends StatelessWidget {
 // 覆盖此函数以构建依赖于动画的当前状态的控件
 @override
 Widget build(BuildContext context) {
  // 获取当前图标主题,创建与此图标主题相同的图标主题
  final IconThemeData iconTheme = IconTheme.of(context).fallback();
  // 返回值,创建一个容器控件
  return new Container(
   // 围绕子控件的填充:每个边都偏移4.0
   margin: const EdgeInsets.all(4.0),
   // 容器宽度:图标主题的宽度减8.0
   width: iconTheme.size - 8.0,
   // 容器高度:图标主题的高度减8.0
   height: iconTheme.size - 8.0,
   // 子控件的装饰:创建一个装饰
   decoration: new BoxDecoration(
    // 背景颜色:图标主题的颜色
    backgroundColor: iconTheme.color
   )
  );
 }
}
// 创建类,菜单演示,继承StatefulWidget(有状态的控件)
class MenusDemo extends StatefulWidget {
 /*
  * 覆盖具有相同名称的超类成员
  * createState方法在树中的给定位置为此控件创建可变状态
  * 子类应重写此方法以返回其关联的State子类新创建的实例
  */
 @override
 _MenusDemoState createState() => new _MenusDemoState();
}
/*
 * 关联State子类的实例
 * 继承State:StatefulWidget(有状态的控件)逻辑和内部状态
 * 继承TickerProviderStateMixin,提供Ticker对象
 */
class _MenusDemoState extends State<MenusDemo> with TickerProviderStateMixin {
 // 类成员,存储底部导航栏的当前选择
 int _currentIndex = 2;
 // 类成员,存储底部导航栏的布局和行为:在点击时会变大
 BottomNavigationBarType _type = BottomNavigationBarType.shifting;
 // 类成员,存储NavigationIconView类的列表
 List<NavigationIconView> _navigationViews;
 /*
  * 在对象插入到树中时调用
  * 框架将为它创建的每个State(状态)对象调用此方法一次
  * 覆盖此方法可以实现此对象被插入到树中的位置的初始化
  * 或用于配置此对象上的控件的位置的初始化
  */
 @override
 void initState() {
  // 调用父类的内容
  super.initState();
  // 在存储NavigationIconView类的列表里添加内容
  _navigationViews = <NavigationIconView>[
   /*
    * 创建NavigationIconView类的实例
    * 传递图标参数
    * 传递标题参数
    * 传递颜色参数
    * 传递Ticker对象
    */
   new NavigationIconView(
    icon: new Icon(Icons.access_alarm),
    title: new Text('成就'),
    color: Colors.deepPurple[500],
    vsync: this,
   ),
   new NavigationIconView(
    icon: new CustomIcon(),
    title: new Text('行动'),
    color: Colors.deepOrange[500],
    vsync: this,
   ),
   new NavigationIconView(
    icon: new Icon(Icons.cloud),
    title: new Text('人物'),
    color: Colors.teal[500],
    vsync: this,
   ),
   new NavigationIconView(
    icon: new Icon(Icons.favorite),
    title: new Text('财产'),
    color: Colors.indigo[500],
    vsync: this,
   ),
   new NavigationIconView(
    icon: new Icon(Icons.event_available),
    title: new Text('设置'),
    color: Colors.pink[500],
    vsync: this,
   ),
  ];
  // 循环调用存储NavigationIconView类的列表的值
  for (NavigationIconView view in _navigationViews)
   // 每次动画控制器的值更改时调用侦听器
   view.controller.addListener(_rebuild);
  // 底部导航栏当前选择的动画控制器的值为1.0
  _navigationViews[_currentIndex].controller.value = 1.0;
 }
 // 释放此对象使用的资源
 @override
 void dispose() {
  // 调用父类的内容
  super.dispose();
  // 循环调用存储NavigationIconView类的列表中的项
  for (NavigationIconView view in _navigationViews)
   // 调用此方法后,对象不再可用
   view.controller.dispose();
 }
 // 动画控制器的值更改时的操作
 void _rebuild() {
  // 通知框架此对象的内部状态已更改
  setState((){
   // 重建,以便为视图创建动画
  });
 }
 // 建立过渡堆栈
 Widget _buildTransitionsStack() {
  // 局部变量,存储不透明度转换的列表
  final List<FadeTransition> transitions = <FadeTransition>[];
  // 循环调用存储NavigationIconView类的列表的值
  for (NavigationIconView view in _navigationViews)
   // 在存储不透明度转换的列表中添加transition函数的返回值
   transitions.add(view.transition(_type, context));
  // 对存储不透明度转换的列表进行排序
  transitions.sort((FadeTransition a, FadeTransition b) {
   final Animation<double> aAnimation = a.listenable;
   final Animation<double> bAnimation = b.listenable;
   // aValue:a的动画值
   double aValue = aAnimation.value;
   // bValue:b的动画值
   double bValue = bAnimation.value;
   /*
    * 将aValue与bValue进行比较
    * 返回一个负整数,aValue排序在bValue之前
    * 返回一个正整数,aValue排序在bValue之后
    */
   return aValue.compareTo(bValue);
  });
  // 返回值,创建层叠布局控件
  return new Stack(children: transitions);
 }
 // 覆盖此函数以构建依赖于动画的当前状态的控件
 @override
 Widget build(BuildContext context) {
  // 局部变量,创建底部导航栏
  final BottomNavigationBar botNavBar = new BottomNavigationBar(
   /*
    * 在底部导航栏中布置的交互项:迭代存储NavigationIconView类的列表
    * 返回此迭代的每个元素的底部导航栏项目
    * 创建包含此迭代的元素的列表
    */
   items: _navigationViews
    .map((NavigationIconView navigationView) => navigationView.item)
    .toList(),
   // 当前活动项的索引:存储底部导航栏的当前选择
   currentIndex: _currentIndex,
   // 底部导航栏的布局和行为:存储底部导航栏的布局和行为
   type: _type,
   // 当点击项目时调用的回调
   onTap: (int index) {
    // 通知框架此对象的内部状态已更改
    setState((){
     // 当前选择的底部导航栏项目,开始反向运行此动画
     _navigationViews[_currentIndex].controller.reverse();
     // 更新存储底部导航栏的当前选择
     _currentIndex = index;
     // 当前选择的底部导航栏项目,开始向前运行此动画
     _navigationViews[_currentIndex].controller.forward();
    });
   }
  );
  // 实现基本的质感设计视觉布局结构
  return new Scaffold(
   // 质感设计应用栏
   appBar: new AppBar(
    // 应用栏中显示的主要控件,包含程序当前内容描述的文本
    title: new Text('底部导航演示'),
    // 在标题控件后显示的控件
    actions: <Widget> [
     // 创建一个显示弹出式菜单的按钮
     new PopupMenuButton<BottomNavigationBarType>(
      // 当用户从此按钮创建的弹出菜单中选择一个值时调用
      onSelected: (BottomNavigationBarType value) {
       // 通知框架此对象的内部状态已更改
       setState((){
        // 存储底部导航栏的布局和行为:选择值
        _type = value;
       });
      },
      // 点击弹出菜单中显示的项目时调用
      itemBuilder: (BuildContext context) => <PopupMenuItem<BottomNavigationBarType>> [
       /*
        * 弹出菜单中的显示项目
        * 返回值:底部导航栏的布局和行为
        * 子控件:文本控件
        */
       new PopupMenuItem<BottomNavigationBarType>(
        value: BottomNavigationBarType.fixed,
        child: new Text('Fixed')
       ),
       new PopupMenuItem<BottomNavigationBarType>(
        value: BottomNavigationBarType.shifting,
        child: new Text('Shifting')
       )
      ]
     )
    ]
   ),
   // 主要内容
   body: new Center(
    // 主要内容:_buildTransitionsStack函数的返回值
    child: _buildTransitionsStack()
   ),
   // 水平的按钮数组,沿着程序的底部显示
   bottomNavigationBar: botNavBar,
  );
 }
}
// 程序入口
void main() {
 // 创建质感设计程序,并放置到主屏幕
 runApp(new MaterialApp(
  // 在窗口管理器中使用此应用程序的单行描述
  title: 'Flutter教程',
  // 程序的默认路由的控件
  home: new MenusDemo(),
 ));
}

Flutter质感设计之底部导航

Flutter质感设计之底部导航

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/hekaiyou/article/details/54138448?locationNum=6&fps=1

延伸 · 阅读

精彩推荐