【Flutter】AppBar、TabBar和TabBarView

🔥 本文由 程序喵正在路上 原创,CSDN首发!
💖 系列专栏:Flutter学习
🌠 首发时间:2024年5月26日
🦋 欢迎关注🖱点赞👍收藏🌟留言🐾

目录

  • AppBar、TabBar和TabBarView
    • MaterialApp去掉debug图标
    • AppBar自定义顶部按钮图标、颜色
    • TabBar组件
    • TabBar、TabBarView实现类似头条顶部导航
    • BottomNavigationBar的页面中使用TabBar
    • PreferredSize组件
    • 自定义KeepAliveWrapper缓存页面
    • 监听TabController改变事件

AppBar、TabBar和TabBarView

MaterialApp去掉debug图标

return MaterialApp(title: 'Flutter Demo',theme: ThemeData(primarySwatch: Colors.blue,),debugShowCheckedModeBanner: false,	//去掉Debug图标home: const HomePage(),
);

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

AppBar 常用属性:

属性描述
leading在标题前面显示的一个控件,在首页通常显示应用的 logo;在其他页面通常显示未返回按钮
title标题,通常显示为当前界面的标题文字,可以放组件
actions通常使用 IconButton 来表示,可以放按钮组
bottom通常放 tabBar,标题下面显示一个 Tab 导航栏
backgroundColor导航背景颜色
iconTheme图标样式
centerTitle标题是否居中显示
import 'package:flutter/material.dart';void main() {runApp(const MyApp());
}class MyApp extends StatelessWidget {const MyApp({super.key});Widget build(BuildContext context) {return MaterialApp(title: 'Flutter Demo',theme: ThemeData(primarySwatch: Colors.blue,),debugShowCheckedModeBanner: false, //去掉Debug图标home: const HomePage(),);}
}class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => _HomePageState();
}class _HomePageState extends State<HomePage> {Widget build(BuildContext context) {return Scaffold(appBar: AppBar(backgroundColor: Colors.red,leading: IconButton(	//左侧按钮icon: const Icon(Icons.menu),onPressed: () {print('menu Pressed');}),title: const Text('AppBar'),actions: [	//右侧按钮IconButton(icon: const Icon(Icons.search),onPressed: () {print('Search Pressed');}),IconButton(icon: const Icon(Icons.more_horiz),onPressed: () {print('more_horiz Pressed');})],),body: const Text("头条滑动导航"),);}
}

在这里插入图片描述

TabBar组件

TabBar 常见属性:

属性描述
tabs显示的标签内容,一般使用 Tab 对象,也可以是其他的 Widget
controllerTabController 对象
isScrollable是否可滚动
indicatorColor指示器颜色
indicatorWeight指示器高度
indicatorPadding底部指示器的Padding
indicator指示器decoration,例如边框等
indicatorSize指示器的大小计算方式,TabBarIndicatorSize.lable:跟文字等宽;TabBarIndicatorSize.tab:跟每个 tab 等宽
labelColor被选中的 label 的颜色
labelStyle被选中的 label 的 style
labelPadding每个 label 的 padding 值
unselectedLabelColor未被选中的 label 的颜色
unselectedLabelStyle未被选中的 label 的 style

TabBar、TabBarView实现类似头条顶部导航

  1. 混入 SingleTickerProviderStateMixin

    class _HomePageState extends State<HomePage>with SingleTickerProviderStateMixin {}
    
  2. 定义 TabController

    late TabController _tabController;//生命周期函数:当组件初始化的时候就会触发//输入inits可快速生成该方法void initState() {super.initState();_tabController = TabController(length: 3, vsync: this);}
    
  3. 配置 TabBarTabBarView

    Scaffoldbottom 属性中配置 TabBar,在 body 属性中配置 TabBarView

    import 'package:flutter/material.dart';void main() {runApp(const MyApp());
    }class MyApp extends StatelessWidget {const MyApp({super.key});Widget build(BuildContext context) {return MaterialApp(title: 'Flutter Demo',theme: ThemeData(primarySwatch: Colors.blue,),debugShowCheckedModeBanner: false, //去掉Debug图标home: const HomePage(),);}
    }class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => _HomePageState();
    }class _HomePageState extends State<HomePage>with SingleTickerProviderStateMixin {late TabController _tabController;//生命周期函数:当组件初始化的时候就会触发//输入inits可快速生成该方法void initState() {super.initState();_tabController = TabController(length: 8, vsync: this);}Widget build(BuildContext context) {return Scaffold(appBar: AppBar(title: const Text('Flutter Demo'),backgroundColor: Colors.blue,leading: IconButton(icon: const Icon(Icons.menu),onPressed: () {print('menu Pressed');}),actions: [IconButton(icon: const Icon(Icons.search),onPressed: () {print('Search Pressed');}),IconButton(icon: const Icon(Icons.more_horiz),onPressed: () {print('more_horiz Pressed');})],bottom: TabBar(isScrollable: true, //导航栏及页面是否可以滚动indicatorColor: Colors.white,indicatorWeight: 2,indicatorPadding: const EdgeInsets.all(5),indicatorSize: TabBarIndicatorSize.tab,indicator: BoxDecoration(color: Colors.white,borderRadius: BorderRadius.circular(10),),labelColor: Colors.blue,unselectedLabelColor: Colors.white,labelStyle: const TextStyle(fontSize: 14),unselectedLabelStyle: const TextStyle(fontSize: 12),controller: _tabController,tabs: const [Tab(child: Text("关注")),Tab(child: Text("推荐")),Tab(child: Text("视频")),Tab(child: Text("财经")),Tab(child: Text("科技")),Tab(child: Text("热点")),Tab(child: Text("国际")),Tab(child: Text("更多")),],),),body: TabBarView(controller: _tabController,children: [ListView(children: const [ListTile(title: Text("我是关注列表"))],),ListView(children: const [ListTile(title: Text("我是推荐列表"))],),ListView(children: const [ListTile(title: Text("我是视频列表"))],),ListView(children: const [ListTile(title: Text("我是财经列表"))],),ListView(children: const [ListTile(title: Text("我是科技列表"))],),ListView(children: const [ListTile(title: Text("我是热点列表"))],),ListView(children: const [ListTile(title: Text("我是国际列表"))],),ListView(children: const [ListTile(title: Text("我是更多列表"))],),],),);}
    }
    

    在这里插入图片描述

BottomNavigationBar的页面中使用TabBar

在这里插入图片描述

回到前面仿闲鱼首页底部导航这个程序,如果我们想在这个页面使用 TabBar,那么我们就需要在 tabs.dart 中的 Scaffoldbody 属性中添加 TarBarView 组件,但是 body 中我们已经写了自动切换页面的代码,无法再添加 TarBarView 组件,这个时候该怎么办呢?

在这里插入图片描述

其实,我们可以来到 home.dart 这个页面,在这里再套一层 Scaffold,然后在这里配置 TarBar,步骤和前面一样,我们将代码复制过来,然后为了让导航栏可以显示在最上面,我们可以将 TarBar 直接写在 title 里面

修改后的 home.dart

import 'package:flutter/material.dart';class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => _HomePageState();
}class _HomePageState extends State<HomePage>with SingleTickerProviderStateMixin {late TabController _tabController;void initState() {super.initState();_tabController = TabController(length: 8, vsync: this);}Widget build(BuildContext context) {return Scaffold(appBar: PreferredSize(preferredSize: const Size.fromHeight(40),child: AppBar(backgroundColor: Colors.white,elevation: 1, //阴影title: SizedBox(height: 30,child: TabBar(isScrollable: true, //导航栏及页面是否可以滚动indicatorColor: Colors.red,labelColor: Colors.red,unselectedLabelColor: Colors.black,labelStyle: const TextStyle(fontSize: 14),unselectedLabelStyle: const TextStyle(fontSize: 14),controller: _tabController,tabs: const [Tab(child: Text("关注")),Tab(child: Text("推荐")),Tab(child: Text("视频")),Tab(child: Text("财经")),Tab(child: Text("科技")),Tab(child: Text("热点")),Tab(child: Text("国际")),Tab(child: Text("更多")),],),),),),body: TabBarView(controller: _tabController,children: [ListView(children: [Padding(padding: const EdgeInsets.all(15),child: Column(children: [Image.network("https://xixi-web-tlias.oss-cn-guangzhou.aliyuncs.com/1.jpg"),const SizedBox(height: 10),Image.network("https://xixi-web-tlias.oss-cn-guangzhou.aliyuncs.com/2.jpg"),const SizedBox(height: 10),Image.network("https://xixi-web-tlias.oss-cn-guangzhou.aliyuncs.com/3.jpg"),const SizedBox(height: 10),Image.network("https://xixi-web-tlias.oss-cn-guangzhou.aliyuncs.com/4.jpg"),const SizedBox(height: 10),Image.network("https://xixi-web-tlias.oss-cn-guangzhou.aliyuncs.com/5.jpg"),const SizedBox(height: 10),Image.network("https://xixi-web-tlias.oss-cn-guangzhou.aliyuncs.com/6.jpg"),],),),],),ListView(children: const [ListTile(title: Text("我是推荐列表"))],),ListView(children: const [ListTile(title: Text("我是视频列表"))],),ListView(children: const [ListTile(title: Text("我是财经列表"))],),ListView(children: const [ListTile(title: Text("我是科技列表"))],),ListView(children: const [ListTile(title: Text("我是热点列表"))],),ListView(children: const [ListTile(title: Text("我是国际列表"))],),ListView(children: const [ListTile(title: Text("我是更多列表"))],),],),);}
}

效果:

在这里插入图片描述

PreferredSize组件

PreferredSize 组件可以配置 appBar 的高度

Scaffold(appBar: PreferredSize(preferredSize: const Size.fromHeight(40),child: AppBar(),),body: TabBarView(),
);

自定义KeepAliveWrapper缓存页面

在前面实现的顶部导航中,如果我们在关注页面滑动到底部,然后我们再点击其他页面,接着我们返回关注页面,会发现它自动恢复到起始的状态。如果我们想让关注页面不恢复,该怎么做呢?

Flutter 中,我们可以通过 AutomaticKeepAliveClientMixin 来快速实现页面缓存功能,但是通过混入的方式实现不是很优雅, 所以我们有必要对AutomaticKeepAliveClientMixin 混入进行封装。

我们将其封装成一个类或者叫组件 KeepAliveWrapper,在 lib 目录下新建 tools 目录,在 tools 下新建 keepAliveWrapper.dart 文件,内容如下:

import 'package:flutter/material.dart';class KeepAliveWrapper extends StatefulWidget {const KeepAliveWrapper({super.key,  this.child, this.keepAlive = true});final Widget? child;final bool keepAlive;State<KeepAliveWrapper> createState() => _KeepAliveWrapperState();
}class _KeepAliveWrapperState extends State<KeepAliveWrapper>with AutomaticKeepAliveClientMixin {Widget build(BuildContext context) {super.build(context);return widget.child!;}bool get wantKeepAlive => widget.keepAlive;void didUpdateWidget(covariant KeepAliveWrapper oldWidget) {if (oldWidget.keepAlive != widget.keepAlive) {// keepAlive 状态需要更新,实现在 AutomaticKeepAliveClientMixin 中updateKeepAlive();}super.didUpdateWidget(oldWidget);}
}

然后,在需要使用的地方 home.dart 导入该文件,在需要缓存的代码外面套上一层 KeepAliveWrapper 即可:

import 'package:flutter/material.dart';
import '../../tools/keepAliveWrapper.dart';	//导入class HomePage extends StatefulWidget {const HomePage({super.key});State<HomePage> createState() => _HomePageState();
}class _HomePageState extends State<HomePage>with SingleTickerProviderStateMixin {late TabController _tabController;void initState() {super.initState();_tabController = TabController(length: 8, vsync: this);}Widget build(BuildContext context) {return Scaffold(appBar: PreferredSize(preferredSize: const Size.fromHeight(40),child: AppBar(backgroundColor: Colors.white,elevation: 1, //阴影title: SizedBox(height: 30,child: TabBar(isScrollable: true, //导航栏及页面是否可以滚动indicatorColor: Colors.red,labelColor: Colors.red,unselectedLabelColor: Colors.black,labelStyle: const TextStyle(fontSize: 14),unselectedLabelStyle: const TextStyle(fontSize: 14),controller: _tabController,tabs: const [Tab(child: Text("关注")),Tab(child: Text("推荐")),Tab(child: Text("视频")),Tab(child: Text("财经")),Tab(child: Text("科技")),Tab(child: Text("热点")),Tab(child: Text("国际")),Tab(child: Text("更多")),],),),),),body: TabBarView(controller: _tabController,children: [//缓存第一个页面KeepAliveWrapper(child: ListView(children: [Padding(padding: const EdgeInsets.all(15),child: Column(children: [Image.network("https://xixi-web-tlias.oss-cn-guangzhou.aliyuncs.com/1.jpg"),const SizedBox(height: 10),Image.network("https://xixi-web-tlias.oss-cn-guangzhou.aliyuncs.com/2.jpg"),const SizedBox(height: 10),Image.network("https://xixi-web-tlias.oss-cn-guangzhou.aliyuncs.com/3.jpg"),const SizedBox(height: 10),Image.network("https://xixi-web-tlias.oss-cn-guangzhou.aliyuncs.com/4.jpg"),const SizedBox(height: 10),Image.network("https://xixi-web-tlias.oss-cn-guangzhou.aliyuncs.com/5.jpg"),const SizedBox(height: 10),Image.network("https://xixi-web-tlias.oss-cn-guangzhou.aliyuncs.com/6.jpg"),],),),],),),ListView(children: const [ListTile(title: Text("我是推荐列表"))],),ListView(children: const [ListTile(title: Text("我是视频列表"))],),ListView(children: const [ListTile(title: Text("我是财经列表"))],),ListView(children: const [ListTile(title: Text("我是科技列表"))],),ListView(children: const [ListTile(title: Text("我是热点列表"))],),ListView(children: const [ListTile(title: Text("我是国际列表"))],),ListView(children: const [ListTile(title: Text("我是更多列表"))],),],),);}
}

监听TabController改变事件

initState 方法中,我们可以通过调用 addListener 方法来监听 TabController 的改变事件,包括点击、滑动等


void initState() {super.initState();_tabController = TabController(length: 8, vsync: this);//监听_tabController的改变事件_tabController.addListener(() {if (_tabController.animation!.value == _tabController.index) {print(_tabController.index); //获取点击或滑动页面的索引值}});
}

当我们点击或滑动到其他页面时,我们就可以获取到对应页面的索引值

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/16020.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FTP协议——BFTPD基本操作(Ubuntu+Win)

1、描述 本机&#xff08;Win10&#xff09;与虚拟机&#xff08;Ubuntu22.04.4&#xff09;上的BFTPD服务器建立FTP连接&#xff0c;执行一些基本操作。BFTPD安装教程&#xff1a;FTP协议——BFTPD安装&#xff08;Linux&#xff09;-CSDN博客 2、 步骤 启动BFTPD。启动文件…

Python文件操作(Excel、PDF、XML、Word)

大家好&#xff0c;在现代数据驱动的世界中&#xff0c;对于数据的处理和管理是至关重要的。Python作为一种强大而灵活的编程语言&#xff0c;提供了丰富的工具和库来处理各种文件格式。本文将探讨Python中的文件操作&#xff0c;重点介绍如何使用Python处理Excel、PDF、XML和W…

RabbitMQ最全使用教程-小白也能看懂

1、队列: 点对点的通信(point - to - point): 消息发送者发送消息,消息代理将其放入到一个队列中&#xff0c;消息接收者从队列中获取消息内容,消息读取后被移除出队列。 2、主题: 发布publish/订阅subscribe 消息通信: 发布者发送消息到主题&#xff0c;多个接收者(订阅者)订阅…

装备制造项目管理软件:奥博思PowerProject项目管理系统

数字化正逐步改变着制造方式和企业组织模式。某制造企业领导层透露&#xff0c;在采用数字化项目管理模式后&#xff0c;企业的发展韧性更加强劲&#xff0c;构筑起了竞争新优势&#xff0c;企业产品研制周期缩短25%&#xff0c;生产效率提升18%。 随着全球经济的发展&#xf…

简单好用的文本识别方法--付费的好用,免费的更有性价比

文章目录 先说付费的进入真题&#xff0c;免费的来喏&#xff01;PixPin微信 先说付费的 直达网址!!! 进入真题&#xff0c;免费的来喏&#xff01; PixPin 商店里就有 使用示例&#xff1a; 可以看到&#xff1a;贴在桌面上的图片可以复制图片中的文字&#xff0c;真的很…

AI语音及其应用

文章目录 一、基本认识二、AI语音应用场景三、真人录音与AI配音的区别四、AI语音创作基本步骤 本文将简单了解下AI语音、应用场景及其优势和创作核心步骤。 一、基本认识 AI语音是指基于人工智能技术开发的语音识别和语音合成系统。语音识别是指计算机识别和理解人类语音的能力…

【机器智能】:AI机器学习在医疗服务的广泛应用与实践案例

目录 引言一&#xff0c;什么是机器学习二&#xff0c;AI在医学影像诊断中的应用三&#xff0c;AI在个性化治疗方案设计中的应用四&#xff0c;医疗图像识别技术五&#xff0c;医疗语言识别技术六&#xff0c;结语 引言 随着人工智能&#xff08;AI&#xff09;和机器学习技术…

SQL注入:原理及示例讲解,配置mysql环境变量,pikachu靶场搭建

SQL注入原理 SQL注入&#xff08;SQL Injection&#xff09;是一种代码注入技术&#xff0c;攻击者通过将恶意的SQL代码插入到应用程序的输入字段中&#xff0c;诱使后台数据库执行这些恶意代码&#xff0c;从而对数据库进行未授权的操作。常见的操作包括获取敏感数据、篡改数…

知能行——考研数学利器

知能行使用体验全记录 首先&#xff0c;我先介绍一下自己&#xff0c;我是2018级的&#xff0c;2022年6月毕业&#xff0c;本科沈阳工业大学&#xff08;双非&#xff09;&#xff0c;今年二战&#xff0c;专业课自动控制原理&#xff0c;数二英二&#xff0c;目标是江南大学控…

[书生·浦语大模型实战营]——第三节:茴香豆:搭建你的 RAG 智能助理

0.RAG 概述 定义&#xff1a;RAG&#xff08;Retrieval Augmented Generation&#xff09;技术&#xff0c;通过检索与用户输入相关的信息片段&#xff0c;并结合外部知识库来生成更准确、更丰富的回答。解决 LLMs 在处理知识密集型任务时可能遇到的挑战, 如幻觉、知识过时和缺…

社交媒体数据恢复:聊天宝

请注意&#xff0c;本教程仅针对聊天宝应用程序&#xff0c;而非其他聊天软件。以下是详细的步骤&#xff1a; 首先&#xff0c;请确保您已经登录了聊天宝应用程序。如果您尚未登录&#xff0c;请使用您的账号登录。 在聊天宝主界面&#xff0c;找到您希望恢复聊天记录的对话框…

小明同学的考试分数统计:总分、平均分与方差计算进阶

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、原始方法介绍与问题发现 原始方法存在的问题 二、优化方案&#xff1a;使用列表简化代…

串口中断原理及实现

一、串口的原理 SM0、SM1——串行口工作模式 SM0SM1模式特点00模式0移位寄存器方式&#xff0c;用于I/O口扩展01模式18位UART,波特率可变10模式29位UART,波特率为时钟频率/32或/6411模式39位UART,波特率可变 TI、RI——发送、接收中断标志位 TITI0 允许发送>TI1 发送完成后…

【全网最全】2024电工杯数学建模A题54页A题保奖成品论文+配套代码

您的点赞收藏是我继续更新的最大动力&#xff01; 一定要点击如下的卡片链接&#xff0c;那是获取资料的入口&#xff01; 【全网最全】2024电工杯数学建模A题成品论文前三题完整解答matlabpy代码等&#xff08;后续会更新成品论文&#xff09;「首先来看看目前已有的资料&am…

出书,是「盖你自己的房子」你知道吗?

出书是「盖你自己的房子」 尊敬的出书盟友&#xff1a; 你好&#xff01;我希望这封信能够激发您对出书和阅读的热情。 在当今信息爆炸的时代&#xff0c;每个人都有机会分享自己的故事、思想和知识。而书籍作为一种流传百年的媒体&#xff0c;依旧承载着无限的力量和影响力…

Java——接口后续

1.Comparable 接口 在Java中&#xff0c;我们对一个元素是数字的数组可以使用sort方法进行排序&#xff0c;如果要对一个元素是对象的数组按某种规则排序&#xff0c;就会用到Comparable接口 当实现Comparable接口后&#xff0c;sort会自动调用Comparable接口里的compareTo 方法…

C++的类和对象

C面向对象的三大特性&#xff1a;封装&#xff0c;继承&#xff0c;多态 万事万物皆可为对象&#xff0c;有其相应的属性和行为 一、封装 1.1 封装的意义 将属性和行为作为一个整体&#xff0c;表现生活中的事物 将属性和行为加以权限控制 在设计类的时候&#xff0c;属性…

Sql语句DQL操作 查询操作单表 多表 子表(嵌套)

DQL 查询语句 查询指定的列 **语法 : ** SELECT [查询列表] FROM 表名结果可以是:表格中的字段,常量,表达式,函数查询的结果是虚拟表格,不可以操作 是只读的可以对查询结果进行 算术运算( - * /);**特点: ** 查询的列表可以是:表中的字段,常量,表达式,函数查询的结果是一个虚…

深入理解 Spring 上下文(Context)层次结构

前言 在使用 Spring 框架进行应用程序开发时&#xff0c;Spring 上下文&#xff08;Context&#xff09;是一个非常重要的概念。Spring 上下文提供了一个环境&#xff0c;用于管理应用程序中的对象&#xff08;通常称为 Bean&#xff09;及其之间的依赖关系。在复杂的应用程序…