theme: cyanosis
持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第 6 天,点击查看活动详情
1. 前言
说起 AppBar
组件,大家都比较熟悉,默认情况下是一个 Material
风格的头部标题栏。可能有人疑惑,这么简单的东西,有什么好说的?其实该组件一些重要的属性很多人都不知道,另外在使用过程中有一些细节,本文将结合 使用
和 源码
来详细探讨一下 AppBar
组件。
如下是 Material2
和 Material3
风格下默认的 AppBar
展示效果:
Material2 | Material3 |
---|---|
AppBar(title: const Text('AppBar 组件')),
1. AppBar 组件的高度
对于 AppBar
来说,最重要的莫过于它的 高度
,那它的高度是如何确定的呢?这就不得不说 PreferredSizeWidget
一族的组件了。如下可见,它实现了 PreferredSizeWidget
类:
如下所示,PreferredSizeWidget
是一个抽象类,其中定义了 preferredSize
抽象 get
方法,返回 Size
对象。也就是说该族的组件是需要预先设定尺寸的:
abstract class PreferredSizeWidget implements Widget {
Size get preferredSize;
}
所以 AppBar
既然实现 PreferredSizeWidget
,就必然实现 preferredSize
方法,返回尺寸。所以根据这个线索可以知道高度是如何确定的:AppBar
中定义了 preferredSize
成员,所以抽象的 get
方法,将获取该成员:
在 AppBar
构造方法中,preferredSize
被赋值为 _PreferredAppBarSize
对象,其中有两个入参: toolbarHeight
,和 bottom
的高度。
如下是 _PreferredAppBarSize
类的定义,它继承自 Size
,是一个专为 AppBar
高度派生的类。Size#fromHeight
构造中,宽度无限大,高度是 toolbarHeight
和 bottomHeight
的和。其中 toolbarHeight
如果为空,会取 kToolbarHeight
, 值为 56
:
---->[AppBar]----
@override
final Size preferredSize;
---->[_PreferredAppBarSize]----
class _PreferredAppBarSize extends Size {
_PreferredAppBarSize(this.toolbarHeight, this.bottomHeight)
: super.fromHeight((toolbarHeight ?? kToolbarHeight) (bottomHeight ?? 0));
final double? toolbarHeight;
final double? bottomHeight;
}
---->[Size#fromHeight]----
const Size.fromHeight(double height) : super(double.infinity, height);
另外 AppBar
是可以指定PreferredSizeWidget
类型的 bottom
组件,在标题的底部展示。如下所示,所以可以说, AppBar
组件的高度就是 toolbarHeight
和 bottom
组件高度之和。
---->[AppBar]----
final PreferredSizeWidget? bottom;
final double? toolbarHeight;
另外,可以通过参数指定 toolbarHeight
的值,如下是 40
的效果,可以看出标题的高度变小,但并不会影响 bottom
。
AppBar(
title: const Text('AppBar 组件'),
toolbarHeight: 40,
),
关于 AppBar
的高度需要注意的就是这些,一般来说 AppBar
作为 Scaffold#appBar
属性的钦定组件使用,不会在外界单独使用。
2. AppBar 组件的部位
一个普通的 AppBar
可以包含如下四个部位, leading
是左侧组件,title
是中间组件,actions
的右侧组件列表。 bottom
是底部组件:
---->[AppBar]----
final PreferredSizeWidget? bottom;
final Widget? leading;
final Widget? title;
final List<Widget>? actions;
通过查看布局效果可以更清晰地看出 AppBar
各部位的占位情况,
另外,还有一个Widlget
类型的 flexibleSpace
属性,在源码实现的过程中,该组件将通过 Stack
叠放在 AppBar
下方。效果如下,如果普通的 AppBar
底部用贴图的需求,可以使用这个属性:
---->[AppBar]----
final Widget? flexibleSpace;
3. 部位相关控制属性
下面介绍一些关于部位的属性: centerTitle
是一个 bool
值,可以控制 title
是否居中显示。这个是在整体的居中,所以 AppBar
的标题栏并不是一个简单的 Row
组件包裹,具体地实现细节,将在源码分析中介绍:
---->[AppBar]----
final bool? centerTitle;
toolbarOpacity
和 bottomOpacity
分别用来控制标题栏和底栏的透明度,取值范围是 [0 ~ 1]
,默认是 1
不透明。一般来说很少有这种需求,了解一下即可:
---->[AppBar]----
final double? toolbarOpacity;
final double? bottomOpacity;
titleSpacing
是一个 double
值,用于控制标题栏和区域左侧的间隔,默认情况下根据 Material
的风格有一定的空间,该值为 16
:
所以想要消除这个间距,让 titleSpacing
置零即可:
final double? titleSpacing;
titleSpacing
是一个 double
值,用于控制左侧 leading
的区域宽度,默认情况下是 56
, 呈正方形 :
final double? leadingWidth;
4. AppBar 样式属性
可以通过 shape
属性设置 AppBar
形状,如下是通过 RoundedRectangleBorder
设置的圆角矩形。关于ShapeBorder
相关的使用,可以参考另一篇文章: 【Path在手,天下我有】。另外 elevation
和 shadowColor
分别表示阴影的深度和阴影颜色:
参数 | 类型 | 描述 |
---|---|---|
shadowColor | Color? | 阴影颜色 |
elevation | double | 影深 |
shape | ShapeBorder? | 形状 |
另外通过去除阴影、设置背景色,也可以很轻松地摆脱 Material
风格。其中通过了 iconTheme
来配置 AppBar
中的默认图标主题,这样如果存在多个按钮,方便统一配置,避免一个个设置的麻烦。actionsIconTheme
的图标样式优先作用于 actions
属性中的组件。
另外,toolbarTextStyle
为工具条区域内的所有文字通过默认样式,titleTextStyle
配置的默认标题文字主题,优先级较高。
参数 | 类型 | 描述 |
---|---|---|
backgroundColor | Color? | 背景色 |
iconTheme | IconThemeData? | 图标样式 |
actionsIconTheme | IconThemeData? | 右侧图标样式 |
titleTextStyle | TextStyle? | 标题文字样式 |
toolbarTextStyle | TextStyle? | 工具条文字样式 |
AppBar(
title: const Text('AppBar 组件'),
leading: BackButton(),
elevation: 0,
backgroundColor: Colors.white,
centerTitle: true,
iconTheme: IconThemeData(color: Colors.black),
titleTextStyle: TextStyle(color: Colors.black,fontSize: 16,fontWeight: FontWeight.bold),
actions: [
IconButton(onPressed: (){}, icon: Icon(Icons.refresh)),
IconButton(onPressed: (){}, icon: Icon(Icons.add)),
],
),
5. AppBar 的使用细节
AppBar
在构造时可以传入 automaticallyImplyLeading
属性,用于控制是否在 leading
为 null
时,根据场景自动添加某些图标:比如 Scafflod
中 drawer
属性非空时,会自动提供 leading
,点击时响应事件打开 drawer
。
还有当跳转界面时,如果使用了 AppBar
并且未提供 leading
,会自动添加返回按钮。如果不想启用个功能,将 automaticallyImplyLeading
置为 false
即可。
在 AppBar
的使用过程中,有一个非常重要,可能很少人注意的一点: AppBar
的背景色可以影响顶部状态栏的颜色。比如默认情况下背景色是蓝色,状态栏是白色:
如果背景色是白色,状态栏就会是黑色,这样就很方便。
如果不使用 AppBar
,也能界面跳着跳着状态栏就错乱了。比如类似下面的情况。通过源码可以知道 AppBar
中会通过 AnnotatedRegion
维护状态栏的颜色。
如果状态栏的颜色和你预期的不同,可以通过 systemOverlayStyle
属性来设置状态栏的颜色,如下 light
会将状态栏图标的颜色变白:
systemOverlayStyle: const SystemUiOverlayStyle(
statusBarIconBrightness:Brightness.light
),
关于 AppBar
的使用基本上就是这些,总的来看, AppBar
算是一个比较优秀的组件,使用很灵活,能满足绝大多数的头部栏使用场景。如果你在日常开发中还自己用 Row
来拼装,那不妨试试 AppBar
组件。下一篇将通过分析 AppBar
源码的实现,来分析一下更细致的实现逻辑,从中吸收一下处理的小技巧。 那本文就到这里,谢谢观看 ~
更多 Flutter 内置组件介绍,欢迎关注 《Flutter 组件集录》 专栏。
@张风捷特烈 2022.10.20 未允禁转
我的 公众号: 编程之王
我的 github 主页
: toly1994328