Android技术知识扣丁学堂Android培训Android开发经验谈

扣丁学堂Android开发Flutter质感设计之底部导航

2018-08-24  本文已影响5人  994d14631d16

  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(),

  ));

  }

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

上一篇 下一篇

猜你喜欢

热点阅读