23、Flutter AppBar TabBar TabBarView

发布时间 2023-12-18 00:08:57作者: 鲤斌

AppBar自定义顶部按钮图标、颜色

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: IconButton(
          //导航左侧图标
          icon: const Icon(Icons.home_max),
          onPressed: () {
            print("左侧点击了左侧");
          },
        ),
        title: const Text("Flutter App"), //标题
        centerTitle: true, // 设置标题居中
        backgroundColor: Colors.yellow, //导航背景颜色
        actions: [
          //导航右侧图标 一个或多个
          IconButton(
            icon: const Icon(Icons.home),
            onPressed: () {
              print("右侧点击了右侧");
            },
          ),
          IconButton(
            icon: const Icon(Icons.safety_check),
            onPressed: () {
              print("右侧点击了右侧");
            },
          ),
        ],
      ),
      backgroundColor: Colors.red, //主体背景颜色
      drawer: const Drawer(
        child: Text("左侧侧边栏"),
      ),
    );
  }
}

Flutter AppBar结合TabBar实现顶部Tab切换

TabBar常见属性:

Tabbar TabBarView实现类似头条顶部导航

class MyHomeApp extends StatefulWidget {
  const MyHomeApp({super.key});

  @override
  State<MyHomeApp> createState() => _MyHomeAppState();
}

class _MyHomeAppState extends State<MyHomeApp>
    with SingleTickerProviderStateMixin {
  late TabController _tabController;

//生命周期函数:当组件初始化的时候就会触发
  void initState() {
    super.initState();
    _tabController = TabController(length: 3, vsync: this);
    _tabController.addListener(() {
      if (_tabController.animation!.value == _tabController.index) {
        print(_tabController.index); //获取点击或滑动页面的索引值
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.red, //导航背景颜色
        bottom: TabBar(

          isScrollable:true, //是否可滚动
          indicatorColor:Colors.yellow, //指示器颜色
          indicatorWeight:5, //指示器高度
          indicatorPadding:EdgeInsets.all(10), //底部指示器的Padding
          indicator:BoxDecoration(  //指示器decoration,例如边框等
            color: Colors.blue,  
            borderRadius: BorderRadius.circular(10) //圆角
          ),
          labelColor: Colors.black, //选中label颜色
          unselectedLabelColor:Colors.yellow, //未选中label颜色
          labelStyle: const TextStyle(
            fontSize: 20
          ),//选中label的Style
          unselectedLabelStyle:const TextStyle(
            fontSize: 15
          ),//未选中label的Style
          indicatorSize:TabBarIndicatorSize.label, //指示器大小计算方式,TabBarIndicatorSize.label跟文字等宽,TabBarIndicatorSize.tab跟每个tab等宽
          controller: _tabController, //注意: 配置controller需要去掉TabBar上const
          tabs: const [
            Tab(
              child: Text("关注"),
            ),
            Tab(
              child: Text("热门"),
            ),
            Tab(
              child: Text("视频"),
            ),
          ],
        ),
      ),
      body: TabBarView(
        controller: _tabController,
        children: [
          const Text("第一个关注"),
          ListView(
            children: const [
              ListTile(
                title: Text("第一个热门"),
              ),
              ListTile(
                title: Text("第二个热门"),
              ),
              ListTile(
                title: Text("第三个热门"),
              ),
            ],
          ),
          const ListTile(title: Text("第一个视频")),
        ],
      ),
      // backgroundColor: Colors.red, //主体背景颜色
    );
  }
}

BottomNavigationBar 的页面中使用Tabbar

class GrownPage extends StatefulWidget {
  const GrownPage({super.key});

  @override
  State<GrownPage> createState() => _GrownPageState();
}

class _GrownPageState extends State<GrownPage>
    with SingleTickerProviderStateMixin {
  late TabController _tabController;
//生命周期函数:当组件初始化的时候就会触发
  void initState() {
    super.initState();
    _tabController = TabController(length: 3, vsync: this);
    _tabController.addListener(() {
      if (_tabController.animation!.value == _tabController.index) {
        print(_tabController.index); //获取点击或滑动页面的索引值
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: TabBar(
          isScrollable: true, //是否可滚动
          controller: _tabController, //注意: 配置controller需要去掉TabBar上const
          tabs: const [
            Tab(
              child: Text("我的关注"),
            ),
            Tab(
              child: Text("热门"),
            ),
            Tab(
              child: Text("视频"),
            ),
          ],
        ),
        centerTitle: true, //是否居中

        backgroundColor: Color.fromARGB(255, 46, 233, 90), //导航背景颜色
      ),
      body: TabBarView(
        controller: _tabController,
        children: [
          const Text("第一个成人关注"),
          ListView(
            children: const [
              ListTile(
                title: Text("第一个成人热门"),
              ),
              ListTile(
                title: Text("第二个热门"),
              ),
              ListTile(
                title: Text("第三个成人热门"),
              ),
            ],
          ),
          const ListTile(title: Text("第一个成人视频")),
        ],
      ),
      // backgroundColor: Colors.red, //主体背景颜色
    );
  }
}

preferredSize组件

PreferredSize可以改变appBar的高度
Scaffold(
appBar: PreferredSize(
preferredSize: Size.fromHeight(50),
child: AppBar(
....
)
),
body: Test(),
)

自定义KeepAliveWrapper 缓存页面

AutomaticKeepAliveClientMixin 可以快速的实现页面缓存功能,但是通过混入的方式实现不是很优
雅, 所以我们有必要对AutomaticKeepAliveClientMixin 混入进行封装
import 'package:flutter/material.dart';

class KeepAliveWrapper extends StatefulWidget {
  const KeepAliveWrapper(
      {Key? key, @required this.child, this.keepAlive = true})
      : super(key: key);
  final Widget? child;
  final bool keepAlive;
  @override
  State<KeepAliveWrapper> createState() => _KeepAliveWrapperState();
}

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

  @override
  bool get wantKeepAlive => widget.keepAlive;
  @override
  void didUpdateWidget(covariant KeepAliveWrapper oldWidget) {
    if (oldWidget.keepAlive != widget.keepAlive) {
// keepAlive 状态需要更新,实现在 AutomaticKeepAliveClientMixin 中
      updateKeepAlive();
    }
    super.didUpdateWidget(oldWidget);
  }
}

监听TabController改变事件

//方法一
//生命周期函数:当组件初始化的时候就会触发  
  void initState() {
    super.initState();
    _tabController = TabController(length: 8, vsync: this);
    _tabController.addListener(() {
       print(_tabController.index); //获取点击或滑动页面的索引值 (两次)
      if (_tabController.animation!.value == _tabController.index) {
        print(_tabController.index); ////获取点击或滑动页面的索引值(一次)
      }
    });
  }

//方法二
   controller: _tabController, //注意: 配置controller需要去掉TabBar上const
     onTap: (index){ //只能监听点击事件;没法点击滑动
     print("点击事件————————————————————:$index");
            },

...