Flutter进阶—质感设计之底部导航

来源:互联网 发布:netcat windows 使用 编辑:程序博客网 时间:2024/04/28 23:32

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

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

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创建一个容器控件,作为一个自定义的图标使用。同时使用质感设计的弹出菜单控件切换底部导航栏的行为和样式。

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

这里写图片描述

这里写图片描述

0 0
原创粉丝点击