扣丁学堂Android开发Flutter质感设计之底部导航
BottomNavigationBar即底部导航栏控件。显示在应用底部的质感设计控件,用于在少量视图中切换。底部导航栏包含多个以标签、图标或两者搭配的形式显示在项目底部的项目,提供了应用程序的顶级视图之间的快速导航。对于较大的屏幕,侧面导航可能更好。
创建navigation_icon_view.dart文件,定义一个NavigationIconView类,用于管理BottomNavigationBarItem(底部导航栏项目)控件的样式、行为与动画。
import'package:flutter/material.dart';
//创建类,导航图标视图
classNavigationIconView{
//导航图标视图的构造函数
NavigationIconView({
//控件参数,传递图标
Widgeticon,
//控件参数,传递标题
Widgettitle,
//控件参数,传递颜色
Colorcolor,
/*
*Ticker提供者
*由类实现的接口,可以提供Ticker对象
*Ticker对象:每个动画帧调用它的回调一次
*/
TickerProvidervsync,
}):_icon=icon,//接收传递的图标
//接收传递的颜色
_color=color,
//创建底部导航栏项目
item=newBottomNavigationBarItem(
//项目的图标
icon:icon,
//项目的标题
title:title
),
//创建动画控制器
controller=newAnimationController(
//动画持续的时间长度:默认情况下主题更改动画的持续时间
duration:kThemeAnimationDuration,
//垂直同步
vsync:vsync,
){
//创建曲线动画
_animation=newCurvedAnimation(
//应用曲线动画的动画
parent:controller,
/*
*正向使用的曲线:
*从0.5
*到1.0结束
*应用的曲线:快速启动并缓和到最终位置的曲线
*/
curve:newInterval(0.5,1.0,curve:Curves.fastOutSlowIn),
);
}
//类成员,存储图标
finalWidget_icon;
//类成员,存储颜色
finalColor_color;
//类成员,底部导航栏项目
finalBottomNavigationBarItemitem;
//类成员,动画控制器
finalAnimationControllercontroller;
//类成员,曲线动画
CurvedAnimation_animation;
/*
*类函数,过渡转换
*BottomNavigationBarType:定义底部导航栏的布局和行为
*BuildContext:处理控件树中的控件
*/
FadeTransitiontransition(BottomNavigationBarTypetype,BuildContextcontext){
//局部变量,存储图标颜色
ColoriconColor;
//如果底部导航栏的位置和大小在点击时会变大
if(type==BottomNavigationBarType.shifting){
//存储颜色作为图标颜色
iconColor=_color;
}else{
/*
*保存质感设计主题的颜色和排版值:
*使用ThemeData来配置主题控件
*使用Theme.of获取当前主题
*/
finalThemeDatathemeData=Theme.of(context);
/*
*如果程序整体主题的亮度很高(需要深色文本颜色才能实现可读的对比度)
*就返回程序主要部分的背景颜色作为图标颜色
*否则返回控件的前景颜色作为图标颜色
*/
iconColor=themeData.brightness==Brightness.light
?themeData.primaryColor
:themeData.accentColor;
}
//返回值,创建不透明度转换
returnnewFadeTransition(
//控制子控件不透明度的动画
opacity:_animation,
//子控件:创建滑动转换过渡
child:newSlideTransition(
/*
*控制子控件位置的动画
*开始值和结束值之间的线性插值<以尺寸的分数表示的偏移量>
*(1.0,0.0)表示Size的右上角
*(0.0,1.0)表示Size的左下角
*/
position:newTween(
//此变量在动画开头的值
begin:constFractionalOffset(0.0,0.02),
//此变量在动画结尾处的值:左上角
end:FractionalOffset.topLeft,
).animate(_animation),//返回给定动画,该动画接受由此对象确定的值
//子控件:创建控制子控件的颜色,不透明度和大小的图标主题
child:newIconTheme(
//用于子控件中图标的颜色,不透明度和大小
data:newIconThemeData(
//图标的默认颜色
color:iconColor,
//图标的默认大小
size:120.0,
),
//子控件
child:_icon,
)
)
);
}
}
再创建main.dart文件。类CustomIcon创建一个容器控件,作为一个自定义的图标使用。同时使用质感设计的弹出菜单控件切换底部导航栏的行为和样式。
import'package:flutter/material.dart';
import'navigation_icon_view.dart';
//创建类,自定义图标,继承StatelessWidget(无状态的控件)
classCustomIconextendsStatelessWidget{
//覆盖此函数以构建依赖于动画的当前状态的控件
@override
Widgetbuild(BuildContextcontext){
//获取当前图标主题,创建与此图标主题相同的图标主题
finalIconThemeDataiconTheme=IconTheme.of(context).fallback();
//返回值,创建一个容器控件
returnnewContainer(
//围绕子控件的填充:每个边都偏移4.0
margin:constEdgeInsets.all(4.0),
//容器宽度:图标主题的宽度减8.0
width:iconTheme.size-8.0,
//容器高度:图标主题的高度减8.0
height:iconTheme.size-8.0,
//子控件的装饰:创建一个装饰
decoration:newBoxDecoration(
//背景颜色:图标主题的颜色
backgroundColor:iconTheme.color
)
);
}
}
//创建类,菜单演示,继承StatefulWidget(有状态的控件)
classMenusDemoextendsStatefulWidget{
/*
*覆盖具有相同名称的超类成员
*createState方法在树中的给定位置为此控件创建可变状态
*子类应重写此方法以返回其关联的State子类新创建的实例
*/
@override
_MenusDemoStatecreateState()=>new_MenusDemoState();
}
/*
*关联State子类的实例
*继承State:StatefulWidget(有状态的控件)逻辑和内部状态
*继承TickerProviderStateMixin,提供Ticker对象
*/
class_MenusDemoStateextendsStatewithTickerProviderStateMixin{
//类成员,存储底部导航栏的当前选择
int_currentIndex=2;
//类成员,存储底部导航栏的布局和行为:在点击时会变大
BottomNavigationBarType_type=BottomNavigationBarType.shifting;
//类成员,存储NavigationIconView类的列表
List_navigationViews;
/*
*在对象插入到树中时调用
*框架将为它创建的每个State(状态)对象调用此方法一次
*覆盖此方法可以实现此对象被插入到树中的位置的初始化
*或用于配置此对象上的控件的位置的初始化
*/
@override
voidinitState(){
//调用父类的内容
super.initState();
//在存储NavigationIconView类的列表里添加内容
_navigationViews=[
/*
*创建NavigationIconView类的实例
*传递图标参数
*传递标题参数
*传递颜色参数
*传递Ticker对象
*/
newNavigationIconView(
icon:newIcon(Icons.access_alarm),
title:newText('成就'),
color:Colors.deepPurple[500],
vsync:this,
),
newNavigationIconView(
icon:newCustomIcon(),
title:newText('行动'),
color:Colors.deepOrange[500],
vsync:this,
),
newNavigationIconView(
icon:newIcon(Icons.cloud),
title:newText('人物'),
color:Colors.teal[500],
vsync:this,
),
newNavigationIconView(
icon:newIcon(Icons.favorite),
title:newText('财产'),
color:Colors.indigo[500],
vsync:this,
),
newNavigationIconView(
icon:newIcon(Icons.event_available),
title:newText('设置'),
color:Colors.pink[500],
vsync:this,
),
];
//循环调用存储NavigationIconView类的列表的值
for(NavigationIconViewviewin_navigationViews)
//每次动画控制器的值更改时调用侦听器
view.controller.addListener(_rebuild);
//底部导航栏当前选择的动画控制器的值为1.0
_navigationViews[_currentIndex].controller.value=1.0;
}
//释放此对象使用的资源
@override
voiddispose(){
//调用父类的内容
super.dispose();
//循环调用存储NavigationIconView类的列表中的项
for(NavigationIconViewviewin_navigationViews)
//调用此方法后,对象不再可用
view.controller.dispose();
}
//动画控制器的值更改时的操作
void_rebuild(){
//通知框架此对象的内部状态已更改
setState((){
//重建,以便为视图创建动画
});
}
//建立过渡堆栈
Widget_buildTransitionsStack(){
//局部变量,存储不透明度转换的列表
finalListtransitions=[];
//循环调用存储NavigationIconView类的列表的值
for(NavigationIconViewviewin_navigationViews)
//在存储不透明度转换的列表中添加transition函数的返回值
transitions.add(view.transition(_type,context));
//对存储不透明度转换的列表进行排序
transitions.sort((FadeTransitiona,FadeTransitionb){
finalAnimationaAnimation=a.listenable;
finalAnimationbAnimation=b.listenable;
//aValue:a的动画值
doubleaValue=aAnimation.value;
//bValue:b的动画值
doublebValue=bAnimation.value;
/*
*将aValue与bValue进行比较
*返回一个负整数,aValue排序在bValue之前
*返回一个正整数,aValue排序在bValue之后
*/
returnaValue.compareTo(bValue);
});
//返回值,创建层叠布局控件
returnnewStack(children:transitions);
}
//覆盖此函数以构建依赖于动画的当前状态的控件
@override
Widgetbuild(BuildContextcontext){
//局部变量,创建底部导航栏
finalBottomNavigationBarbotNavBar=newBottomNavigationBar(
/*
*在底部导航栏中布置的交互项:迭代存储NavigationIconView类的列表
*返回此迭代的每个元素的底部导航栏项目
*创建包含此迭代的元素的列表
*/
items:_navigationViews
.map((NavigationIconViewnavigationView)=>navigationView.item)
.toList(),
//当前活动项的索引:存储底部导航栏的当前选择
currentIndex:_currentIndex,
//底部导航栏的布局和行为:存储底部导航栏的布局和行为
type:_type,
//当点击项目时调用的回调
onTap:(intindex){
//通知框架此对象的内部状态已更改
setState((){
//当前选择的底部导航栏项目,开始反向运行此动画
_navigationViews[_currentIndex].controller.reverse();
//更新存储底部导航栏的当前选择
_currentIndex=index;
//当前选择的底部导航栏项目,开始向前运行此动画
_navigationViews[_currentIndex].controller.forward();
});
}
);
//实现基本的质感设计视觉布局结构
returnnewScaffold(
//质感设计应用栏
appBar:newAppBar(
//应用栏中显示的主要控件,包含程序当前内容描述的文本
title:newText('底部导航演示'),
//在标题控件后显示的控件
actions:[
//创建一个显示弹出式菜单的按钮
newPopupMenuButton(
//当用户从此按钮创建的弹出菜单中选择一个值时调用
onSelected:(BottomNavigationBarTypevalue){
//通知框架此对象的内部状态已更改
setState((){
//存储底部导航栏的布局和行为:选择值
_type=value;
});
},
//点击弹出菜单中显示的项目时调用
itemBuilder:(BuildContextcontext)=>>[
/*
*弹出菜单中的显示项目
*返回值:底部导航栏的布局和行为
*子控件:文本控件
*/
newPopupMenuItem(
value:BottomNavigationBarType.fixed,
child:newText('Fixed')
),
newPopupMenuItem(
value:BottomNavigationBarType.shifting,
child:newText('Shifting')
)
]
)
]
),
//主要内容
body:newCenter(
//主要内容:_buildTransitionsStack函数的返回值
child:_buildTransitionsStack()
),
//水平的按钮数组,沿着程序的底部显示
bottomNavigationBar:botNavBar,
);
}
}
//程序入口
voidmain(){
//创建质感设计程序,并放置到主屏幕
runApp(newMaterialApp(
//在窗口管理器中使用此应用程序的单行描述
title:'Flutter教程',
//程序的默认路由的控件
home:newMenusDemo(),
));
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持扣丁学堂。