Flutter学习笔记18- BottomNavigationBar 的页面中使用Tabbar

学习视频地址:https://www.bilibili.com/video/BV1S4411E7LY?p=37&vd_source=cee744cae4ead27f8193fc7904647073

学习笔记
本篇基于Flutter学习笔记15和17,Flutter学习笔记15使用了BottomNavigationBar,Flutter学习笔记17使用了TabBar,本节则是将二者结合起来。
在开始前,你需要根据学习笔记15搭建起一个拥有5个tab的页面
并将学习笔记17中的HomePage放到./tabs/home.dart中
运行起来
在这里插入图片描述
实在是太丑了,本节就要在此基础上给美美容。

1.去掉home页面的appbar
直接将TabBar放到AppBar的title部分

import 'package:flutter/material.dart';

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage>
    with SingleTickerProviderStateMixin {
  late TabController _tabController;

  
  void initState() {
    super.initState();
    _tabController = TabController(length: 3, vsync: this);
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        title: TabBar(
          tabs: [Text("推荐"), Text("新闻"), Text("视频")],
          controller: _tabController,
          isScrollable: true,
          indicatorColor: Colors.red,
          indicatorWeight: 10,
          indicatorSize: TabBarIndicatorSize.tab,
          // indicatorPadding: EdgeInsets.all(2),
          labelColor: Colors.black,
          labelStyle: TextStyle(fontSize: 20),
          unselectedLabelColor: Colors.white,
          unselectedLabelStyle: TextStyle(fontSize: 10),
        ),
        backgroundColor: Colors.green,
      ),
      body: TabBarView(
        controller: _tabController,
        children: [Text("推荐"), Text("新闻"), Text("视频")],
      ),
    );
  }
}

看效果
在这里插入图片描述

2.太高了?使用PreferredSize组件改变appbar高度

import 'package:flutter/material.dart';

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage>
    with SingleTickerProviderStateMixin {
  late TabController _tabController;

  
  void initState() {
    super.initState();
    _tabController = TabController(length: 3, vsync: this);
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: PreferredSize(
        preferredSize: Size.fromHeight(40),
        child: AppBar(
          centerTitle: true,
          title: TabBar(
            tabs: [Text("推荐"), Text("新闻"), Text("视频")],
            controller: _tabController,
            isScrollable: true,
            indicatorColor: Colors.red,
            // indicatorWeight: 10,
            indicatorSize: TabBarIndicatorSize.label,
            // indicatorPadding: EdgeInsets.all(2),
            labelColor: Colors.red,
            // labelStyle: TextStyle(fontSize: 20),
            unselectedLabelColor: Colors.black,
            // unselectedLabelStyle: TextStyle(fontSize: 0),
          ),
          backgroundColor: Colors.white,
        ),
      ),
      body: TabBarView(
        controller: _tabController,
        children: [Text("推荐"), Text("新闻"), Text("视频")],
      ),
    );
  }
}

显示效果
在这里插入图片描述

3.自定义KeepAliveWrapper实现缓存页面

import 'package:flutter/material.dart';

class KeepAliveWrapper extends StatefulWidget {
  final Widget? child; //必须传子控件
  final bool keepAlive; //是否缓存

  const KeepAliveWrapper(
      {Key? key,  this.child, this.keepAlive = true})
      : super(key: key);

  
  _KeepAliveWrapperState createState() => _KeepAliveWrapperState();
}

class _KeepAliveWrapperState extends State<KeepAliveWrapper>
    with AutomaticKeepAliveClientMixin {
  
  Widget build(BuildContext context) {
    return widget.child!; //
  }

  
  // TODO: implement wantKeepAlive
  bool get wantKeepAlive => widget.keepAlive;
}

用法:
这里的缓存的意思是:当页面被切换回来时,还能保持之前的状态。

body: TabBarView(
        controller: _tabController,
        children: [
          KeepAliveWrapper(
            child: ListView(
              children: [
                ListTile(
                  title: Text("我是列表1"),
                ),
                ListTile(
                  title: Text("我是列表1"),
                ),
                ListTile(
                  title: Text("我是列表1"),
                ),
                ListTile(
                  title: Text("我是列表1"),
                ),
                ListTile(
                  title: Text("我是列表1"),
                ),
                ListTile(
                  title: Text("我是列表1"),
                ),
                ListTile(
                  title: Text("我是列表1"),
                ),
                ListTile(
                  title: Text("我是列表1"),
                ),
                ListTile(
                  title: Text("我是列表1"),
                ),
                ListTile(
                  title: Text("我是列表5"),
                ),
                ListTile(
                  title: Text("我是列表4"),
                ),
                ListTile(
                  title: Text("我是列表3"),
                ),
              ],
            ),
          ),
          Text("新闻"),
          Text("视频")
        ],
      ),

我用KeepAliveWrapper包裹了一下推荐界面的ListView,这样Listview被划出界面,再被划回界面时,还会保持上次的滚动位置。

4.监听当前打开的是哪个tab

在_HomePageState的initState方法里给tabcontroller添加监听事件


  void initState() {
    super.initState();
    _tabController = TabController(length: 3, vsync: this);
    _tabController.addListener(() {
      print(_tabController.index);
    });
  }

得到的结果却是
在这里插入图片描述
切换页面时,会一下子输出两个一样的index
当点击tab时,会输出一个index,然后tab开始滚动到你所点击的位置,又会输出一个。
所以我需要给打印方法加点条件

 _tabController.addListener(() {
      // ! 类型断言,表示肯定不为空
      if (_tabController.animation!.value == _tabController.index) {
        print(_tabController.index);
      }
    });

此时,只有切换滚动动画结束,才会输出index
在这里插入图片描述

5.最后,销毁资源

 
  void dispose() {
    super.dispose();
    _tabController.dispose();
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值