Flutter顶部导航栏以及ListView简单应用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/chunqiuwei/article/details/85472586

学习flutter除了官方文档之外,其官方本身的examples组织的也很好,算是学习的极好的资料。本篇博文就是摘取的其examples目录下的flutter_gallery项目进行研读和学习。本篇博文摘取了gallery下的调色版的代码进行分析解读,算是一个学习笔记。其代码被博主发挥了拿来注意的精神放在了自己的github上,对关键代码进行了注释。

运行效果如下所示:
在这里插入图片描述
整个页面分成两个部分:导航栏和对应导航tab下的ListView组成。功能也很简单,就是显示一些导航tab下的颜色值。

通过这个sample可以了解:
1)导航栏的简单使用
2)ListView的简单使用
3)MaterialColor的简单使用
4)flutter的整体项目架构


在开始之前,建议读者阅读Material Design的三类颜色,对primaryColor和accentColor有个基本的认知。在Flutter中用MaterialColor,MaterialAccentColor,Colors三个类来供我们使用。比如红色的primaryColor定义了如下代码:

  static const MaterialColor red = MaterialColor(
    _redPrimaryValue,
    <int, Color>{
       50: Color(0xFFFFEBEE),
      100: Color(0xFFFFCDD2),
      200: Color(0xFFEF9A9A),
      300: Color(0xFFE57373),
      400: Color(0xFFEF5350),
      500: Color(_redPrimaryValue),
      600: Color(0xFFE53935),
      700: Color(0xFFD32F2F),
      800: Color(0xFFC62828),
      900: Color(0xFFB71C1C),
    },
  );

而红色的accentColor则表示如下:

  static const MaterialAccentColor redAccent = MaterialAccentColor(
    _redAccentValue,
    <int, Color>{
      100: Color(0xFFFF8A80),
      200: Color(_redAccentValue),
      400: Color(0xFFFF1744),
      700: Color(0xFFD50000),
    },
  );

因为上面red和redAccent 两个静态变量都在Colors类里面定义,所以我们可以这么使用:

MaterialColor red = Colors.red;
MaterialColor red50=Collors.red[50];
MaterialAccentColor redAccent=Colors.redAccent;
MaterialAccentColor redAccent100=Colors.redAccent[100];

文章开头的图片中的listView的item展示的就是颜色primaryColor 50,100-900,accentColor 100,200,400,700的颜色值。


有上图所示,这个简单的demo显示了各个颜色的对应primaryColor和accentColor组成的列表。所以用一个调色板对象_Palette来表示(Palette前面的下滑线表明该类为私有,类似有private):

//Palette:调色板对象
class _Palette {
  _Palette({ this.name, this.primary, this.accent});

  final String name;
  //primaryColor
  final MaterialColor primary;
  //accent color
  final MaterialAccentColor accent;
}

并且初始化了一个数据集合:
在这里插入图片描述
其中_allPalettes的name用来构建导航栏的各个tab.


在Flutter的app中你能看到的任意一个元素都是一个Widget,那么我们怎么将_allPalettes集合中的数据转换成一个个Wiget呢?集合有一个map方法可以帮我们做一个映射。所以上图导航栏的各个tab标签就是这么生成的

 tabs: _allPalettes.map<Widget>((_Palette palette) => Tab(text: palette.name)
            ).toList(),

上面一行代码就是将_allPalettes集合里面的数据遍历其name属性,然后生成一个widget集合,确切地说是Tab对象的集合(Tab也是个Widget),交给导航栏的tabs属性使用。
导航栏完整代码如下:

 bottom: TabBar(
            isScrollable: true,
            //生成导航栏的每一个tab
            tabs: _allPalettes.map<Widget>((_Palette palette) => Tab(text: palette.name)
            ).toList(),
          ),
        ),

同理,对应tab下的页面代码如下所示:

//导航栏各个tab对应的页面
        body: TabBarView(
          children: _allPalettes.map<Widget>((_Palette palette) {
            return _PaletteTabView(colors: palette);
          }).toList(),
        ),
      ),

注意,每个tab下对应的页面是这样一个Widget对象:它是一个自定义的Widget,名字叫_PaletteTabView,该Widget里面有一个ListView,用来渲染如上图所示的结果页面。

这样的话,点击各个tab,就会跳转到对应的_PaletteTabView,我们无需像Android那样设个OnSelectedListener或者onClickListener监听,Flutter帮我们做好了这样的工作。


上面说了_PaletteTabView返回的是一个ListView,其build方法如下:

 return ListView(
      //设置item的高度
      itemExtent: _itemHeight,
      //<Widget>[]数组
      children: colorItems,
    );

代码也很简单,我们通过itemExtent设置了item的高度;然后ListView的各个item通过children属性来配置,children接受的类型是一个Widget[],那么上面的colorItems是如何生成的呢?说这个问题之前,先看看其Item对象如下实现:

  return Semantics(
      container: true,
      child: Container(
        //因为在listView中已经设置了高度,所以这个高度相当于match_parent
        height: _itemHeight,
        padding: const EdgeInsets.symmetric(horizontal: 16.0),
        //背景色:展示primaryColor或者accentColor
        color: color,
        child: SafeArea(
          top: false,
          bottom: false,
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
             //上图每个item左边的文本信息
              Text('$prefix$index'),
              //上图每个item右边的颜色值信息
              Text(colorString()),
            ],
          ),
        ),
      ),
    );

那么ListView中对应的colorsItem生成的代码如下:
在这里插入图片描述
从上面的代码中也可以看出,listView的item可以是任意样式的item,比较灵活,而不像android的recyclerView那样需要设置不同的ViewHolder。
到此为止,本篇博文到此结束。如有不当之处欢迎批评指正。
代码传送门

猜你喜欢

转载自blog.csdn.net/chunqiuwei/article/details/85472586