AppBar的屬性
AppBar({
Key key,
this.leading,
this.automaticallyImplyLeading = true,
this.title,
this.actions,
this.flexibleSpace,
this.bottom,
this.elevation,
this.backgroundColor,
this.brightness,
this.iconTheme,
this.textTheme,
this.primary = true,
this.centerTitle,
this.titleSpacing = NavigationToolbar.kMiddleSpacing,
this.toolbarOpacity = 1.0,
this.bottomOpacity = 1.0,
}) : assert(automaticallyImplyLeading != null),
assert(elevation == null || elevation >= 0.0),
assert(primary != null),
assert(titleSpacing != null),
assert(toolbarOpacity != null),
assert(bottomOpacity != null),
preferredSize = Size.fromHeight(kToolbarHeight + (bottom?.preferredSize?.height ?? 0.0)),
super(key: key);
大體思路就是繼承一個 PreferredSize 類苛让,內(nèi)部通過 Container + decoration 實(shí)現(xiàn)自己需要的效果握爷。(在 Scaffold 類中 appBar 參數(shù)需要一個實(shí)現(xiàn) PreferredSizeWidget 的對象)
文章中的代碼這里貼出來
Widget build(BuildContext context) {
return new Scaffold(
appBar: new PreferredSize(
child: new Container(
padding: new EdgeInsets.only(
top: MediaQuery.of(context).padding.top
),
child: new Padding(
padding: const EdgeInsets.only(
left: 30.0,
top: 20.0,
bottom: 20.0
),
child: new Text(
'Arnold Parge',
style: new TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.w500,
color: Colors.white
),
),
),
decoration: new BoxDecoration(
gradient: new LinearGradient(
colors: [
Colors.red,
Colors.yellow
]
),
boxShadow: [
new BoxShadow(
color: Colors.grey[500],
blurRadius: 20.0,
spreadRadius: 1.0,
)
]
),
),
preferredSize: new Size(
MediaQuery.of(context).size.width,
150.0
),
),
body: new Center(
child: new Text('Hello'),
),
);
}
AppBar內(nèi)部實(shí)現(xiàn)
class AppBar extends StatefulWidget implements PreferredSizeWidget
Appbar 繼承了 StatefulWidget 實(shí)現(xiàn)了 PreferredSizeWidget ,所以我們直接看它的 State -> _AppBarState 吼鳞。
直接去看 build 方法的返回,從后向前,看 AppBar 是如何實(shí)現(xiàn)的绅这。
@override
Widget build(BuildContext context) {
// 省略部分代碼,后面再看
...
final Brightness brightness = widget.brightness
?? appBarTheme.brightness
?? themeData.primaryColorBrightness;
final SystemUiOverlayStyle overlayStyle = brightness == Brightness.dark
? SystemUiOverlayStyle.light
: SystemUiOverlayStyle.dark;
return Semantics( // 輔助功能相關(guān)
container: true,
child: AnnotatedRegion<SystemUiOverlayStyle>( // 處理主題相關(guān)在辆,狀態(tài)欄文字顏色
value: overlayStyle,
child: Material( // Material 控件证薇,處理顏色度苔,陰影等效果
color: widget.backgroundColor
?? appBarTheme.color
?? themeData.primaryColor,
elevation: widget.elevation
?? appBarTheme.elevation
?? _defaultElevation,
child: Semantics( // child里面才是真正的內(nèi)容,我們看內(nèi)部的appBar的實(shí)現(xiàn)浑度。
explicitChildNodes: true,
child: appBar,
),
),
),
);
}
返回了一個控件寇窑,處理了明暗主題,顏色箩张,陰影甩骏,子控件,這里我們不想用這個顏色伏钠,再通過查看 child 能否設(shè)置顏色横漏。
這里的 appBar 是在上面定義的:
Widget appBar = ClipRect( // 用矩形剪輯其子widget
child: CustomSingleChildLayout( // 通過deleagate 來約束子widget
delegate: const _ToolbarContainerLayout(), // 這里的布局是一個寬充滿,高度為kkToolbarHeight高度
child: IconTheme.merge( // 處理IconTheme
data: appBarIconTheme,// 通過判斷熟掂,處理iconTheme的取值
child: DefaultTextStyle( // 文字樣式
style: sideStyle, // 通過判斷傳入的textTheme處理style取值
child: toolbar,
),
),
),
);
這里可以看到缎浇,這里就是包裝了一個 toolbar ,我們繼續(xù)看 toolbar :
// 這里是一個NavigationToolbar赴肚,我們設(shè)置的leading素跺,title在這里使用
final Widget toolbar = NavigationToolbar(
leading: leading,
middle: title,
trailing: actions,
centerMiddle: widget._getEffectiveCenterTitle(themeData),
middleSpacing: widget.titleSpacing,
);
關(guān)于 appBar 內(nèi)部還進(jìn)行一些處理,如處理 bottom 誉券,增加 SafeArea 等處理指厌,這里不做展開了
if (widget.bottom != null) { // bottom
appBar = Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Flexible(
child: ConstrainedBox(
constraints: const BoxConstraints(maxHeight: kToolbarHeight),
child: appBar,
),
),
widget.bottomOpacity == 1.0 ? widget.bottom : Opacity(
opacity: const Interval(0.25, 1.0, curve: Curves.fastOutSlowIn).transform(widget.bottomOpacity),
child: widget.bottom,
),
],
);
}
// The padding applies to the toolbar and tabbar, not the flexible space.
if (widget.primary) { // SafeArea
appBar = SafeArea(
top: true,
child: appBar,
);
}
appBar = Align( // Alignment.topCenter
alignment: Alignment.topCenter,
child: appBar,
);
if (widget.flexibleSpace != null) { // flexibleSpace效果
appBar = Stack(
fit: StackFit.passthrough,
children: <Widget>[
widget.flexibleSpace,
appBar,
],
);
}
通過這里我們知道了,其實(shí) AppBar 中踊跟,顏色是在 Material 中設(shè)置的踩验,我們常用的設(shè)置是在 toolbar 中進(jìn)行使用的,所以最簡單的漸變色處理方式就是將 Material 的child 包一層做顏色處理商玫,不去修改現(xiàn)有部分箕憾。
代碼實(shí)現(xiàn)
代碼很簡單,將AppBar的代碼拷貝出來進(jìn)行修改拳昌,這里的類名為GradientAppBar金踪。
在自定義的 GradientAppBar 的構(gòu)造方法中增加漸變顏色的初始值鸵荠,和終止值口渔。
GradientAppBar({
...
this.gradientStart,
this.gradientEnd,
}) : assert(automaticallyImplyLeading != null),
...
super(key: key);
final Color gradientStart;
final Color gradientEnd;
再將 _AppBarState 類的代碼拷貝出來饺窿,這里的類名是 _GradientAppBarState (記得修改 createState 方法)。
然后在修改對 build 方法 return 中 child 進(jìn)行包裝沈矿,使用傳入的顏色作為漸變色背景上真。
// 添加到build方法最后,return之前羹膳,通過使用decoration實(shí)現(xiàn)顏色的漸變
if (widget.gradientStart != null && widget.gradientEnd != null) {
appBar = Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [widget.gradientStart, widget.gradientEnd]),
),
child: appBar,
);
}
再進(jìn)行處理 Material 的 顏色
return Material(
// 判斷是否使用漸變色
color: widget.gradientStart != null && widget.gradientEnd != null
? Colors.transparent
: widget.backgroundColor ??
appBarTheme.color ??
themeData.primaryColor,
elevation: widget.elevation ?? appBarTheme.elevation ?? _defaultElevation,
child: appBar, // 使用包裝后的appBar
);
這樣就實(shí)現(xiàn)了漸變效果谷羞。
使用 GradientAppBar ,就是將原來使用 AppBar 替換為 GradientAppBar 溜徙。
return Scaffold(
appBar: PreferredSize(
child: GradientAppBar(
gradientStart: Color(0xFF49A2FC),
gradientEnd: Color(0xFF2171F5),
title: Text(widget.title),
leading: Icon(Icons.ac_unit),
),
preferredSize: Size.fromHeight(400),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);