Flutter(43):Cupertino组件之CupertinoTabScaffold、CupertinoTabBar、CupertinoTabView

Flutter教学目录持续更新中

Github源代码持续更新中

1.介绍

  • CupertinoTabScaffold:标签式iOS应用程序的结构。将选项卡栏放在内容选项卡之上
  • CupertinoTabBar:iOS风格的底部选项卡。 通常和CupertinoTabScaffold一起使用。
  • CupertinoTabView:支持选项卡间并行导航项卡的根内容。通常与CupertinoTabScaffolde一起使用

2.CupertinoTabScaffold

  • tabBar:底部选项卡
  • tabBuilder:底部选项卡对应的根内容
  • controller:控制器
  • backgroundColor:背景色
  • resizeToAvoidBottomInset = true:键盘是否顶起页面

3.CupertinoTabBar

  • items:子widget
  • onTap:点击事件
  • currentIndex = 0:当前位置
  • backgroundColor:背景色
  • activeColor:选中颜色
  • inactiveColor = _kDefaultTabBarInactiveColor:未选中颜色
  • iconSize = 30.0:大小
  • border:边框

4.CupertinoTabView

  • builder:根内容
  • navigatorKey:构建的navigatorKey
  • defaultTitle:默认路由标题
  • routes:路由表
  • onGenerateRoute:可以做路由拦截
  • onUnknownRoute:未知路由
  • navigatorObservers = const <NavigatorObserver>[]:

5.使用

  • 由于本教程还没有对navigator,route进行讲解,所以这里暂时不对跟这两个有关系的参数进行深入剖析,在后面的教程中再去深入讲解,目前做个简单了解就可以了
  • 这里CupertinoTabView里面的routes跟MaterialApp/CupertinoApp里面的routes用法是一样的,但是作用域是不同的,可以理解为嵌套型路由。这个跟ios开发中是一样的,底部tab对应页面,每个页面可以嵌套自己的导航路由系统,例如在首页容器中进行页面的跳转;对于android开发就像是activity中嵌套fragment,fragment跳转fragment,对这些fragment做了压栈出栈处理差不多;这样理解起来就比较好懂一点了
  • 这里就先讲解这么多,下面我们来看看具体的实现

5.1.CupertinoTabView嵌套型路由跳转

这种就是在CupertinoTabView内部再指定一套路由表,实现内部导航。这种情况下HomeItemPage是嵌套在CupertinoTabScaffoldPage页面内部的,所以HomeItemPage的点击事件‘下一个页面’=》Navigator.pushNamed(context, Constant.homeHomePage);这个在没有配置CupertinoTabView的routes的时候是不起作用的,因为这是嵌套导航。

1602234680(1).png
1602234694(1).png
class _CupertinoTabScaffoldPageState extends State<CupertinoTabScaffoldPage> {

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('CupertinoTabScaffold'),
      ),
      body: CupertinoTabScaffold(
        tabBar: CupertinoTabBar(
          items: [
            BottomNavigationBarItem(
              icon: Icon(Icons.home),
              title: Text('首页'),
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.mail),
              title: Text('邮件'),
            ),
          ],
        ),
        tabBuilder: (BuildContext context, int index) {
          return CupertinoTabView(
            builder: (context) {
               if (index == 0) {
                 return HomeItemPage();
               } else {
                 return EmailItemPage();
               }
            },
             routes: {
               Constant.homeHomePage: (context) => HomePage(),
             },
          );
        },
      ),
    );
  }
}

class HomeItemPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _HomeItemPageState();
  }
}

class _HomeItemPageState extends State<HomeItemPage>
    with WidgetsBindingObserver, AutomaticKeepAliveClientMixin<HomeItemPage> {
  var _count = 0;

  @override
  void initState() {
    print('_HomeItemPageState initState');
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void didChangeDependencies() {
    print('_HomeItemPageState didChangeDependencies');
    super.didChangeDependencies();
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);
    print('_HomeItemPageState build');
    return Container(
      padding: EdgeInsets.all(10),
      child: Column(
        children: [
          Text('首页'),
          Text('num:$_count'),
          RaisedButton(
            onPressed: () {
              _count++;
              setState(() {});
            },
            child: Text('num++'),
          ),
          RaisedButton(
            onPressed: () {
              Navigator.pushNamed(context, Constant.homeHomePage);
            },
            child: Text('下一个页面'),
          ),
          RaisedButton(
            onPressed: () {
              setState(() {

              });
            },
            child: Text('刷新页面'),
          ),
        ],
      ),
    );
  }

  @override
  void deactivate() {
    super.deactivate();
    print('_HomeItemPageState deactivate');
  }

  @override
  void didUpdateWidget(HomeItemPage oldWidget) {
    print('_HomeItemPageState didUpdateWidget');
    super.didUpdateWidget(oldWidget);
  }

  @override
  void dispose() {
    print('_HomeItemPageState dispose');
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void reassemble() {
    super.reassemble();
    print('_HomeItemPageState reassemble');
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    print('_HomeItemPageState didChangeAppLifecycleState $state');
    super.didChangeAppLifecycleState(state);
  }

  @override
  bool get wantKeepAlive => true;
}

5.2.CupertinoTabView非嵌套型路由跳转

那么问题来了,我不想嵌套在CupertinoTabScaffoldPage内,我要做平常的跳转呢。这个也好办,最简单直接的就是看Navigator持有的context是谁的,如果是来自CupertinoTabView那么就是嵌套导航,那只要不来自CupertinoTabView不就可以了,使用CupertinoTabScaffoldPage的context不就可以了吗,这样就是熟悉的味道了。


1602236370(1).png
1602236379(1).png
class _CupertinoTabScaffoldPageState extends State<CupertinoTabScaffoldPage> {

  _jump() {
    Navigator.of(context).pushNamed(Constant.homeHomePage);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('CupertinoTabScaffold'),
      ),
      body: CupertinoTabScaffold(
        tabBar: CupertinoTabBar(
          items: [
            BottomNavigationBarItem(
              icon: Icon(Icons.home),
              title: Text('首页'),
            ),
            BottomNavigationBarItem(
              icon: Icon(Icons.mail),
              title: Text('邮件'),
            ),
          ],
        ),
        tabBuilder: (BuildContext context, int index) {
          return CupertinoTabView(
            builder: (context) {
              return Center(
                child: RaisedButton(
                  onPressed: () {
                    _jump();
                  },
                  child: Text('next'),
                ),
              );
            },
          );
        },
      ),
    );
  }
}

这一节又是涉及到了路由导航的问题,这里目前还是不展开深入讲解了,后面的教程中再详细说。

到了这里Cupertino组件组件基本上就是讲完了,内容比Material组件少很多,我想谷歌我是希望推广Material组件吧。后面我们会开始对布局组件,滚动组件做介绍,前面的教程也讲解了一点,后面会做更为仔细的介绍。

下一节:Layout组件之Container

Flutter(44):Layout组件之Container

Flutter教学目录持续更新中

Github源代码持续更新中

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343