有點坑的leading
我在項目中遇到這樣一個問題,設置appBar
的 leading
的時候報錯,我定義的leading widget結(jié)構(gòu)如下圖紅框中所示:
image.png
然而報錯、報錯一直報錯,大致錯誤日志是超出多少像素,我依次減少紅框中文字的字符數(shù),報錯log中提示的超出數(shù)量越來越小,看起來像是leading被限制了寬度?
flutter是開源的,這真是極好的,點進去看看...
class AppBar extends StatefulWidget implements PreferredSizeWidget
AppBar({
Key key,
this.leading,
)}
直接看重點位置,即創(chuàng)建leading的位置
Widget leading = widget.leading;
if (leading == null && widget.automaticallyImplyLeading) {
if (hasDrawer) {
leading = IconButton(
icon: const Icon(Icons.menu),
onPressed: _handleDrawerButton,
tooltip: MaterialLocalizations.of(context).openAppDrawerTooltip,
);
} else {
if (canPop)
leading = useCloseButton ? const CloseButton() : const BackButton();
}
}
if (leading != null) {
// 注意此處,leading被設置為一個最大寬度 _kLeadingWidth,看起來我們的猜測是正確的。
leading = ConstrainedBox(
constraints: const BoxConstraints.tightFor(width: _kLeadingWidth),
child: leading,
);
}
那么 _kLeadingWidth又是什么多少?依次尋找往下點
const double _kLeadingWidth = kToolbarHeight; // So the leading button is square.
/// The height of the toolbar component of the [AppBar].
const double kToolbarHeight = 56.0;
很明顯,leading被限制了最寬56,那么默認的AppBar很明顯無法滿足我的需求,so,自定義走起。
自定義AppBar
上面的代碼中可以看到,AppBar只是實現(xiàn)了 PreferredSizeWidget接口
class AppBar extends StatefulWidget implements PreferredSizeWidget
那么我們也可以從這進行入手,自定義一個實現(xiàn)了 PreferredSizeWidget的Widget
具體代碼并不多,比你想象的簡單,直接上代碼,
import 'package:flutter/material.dart';
/// 這是一個可以指定SafeArea區(qū)域背景色的AppBar
/// PreferredSizeWidget提供指定高度的方法
/// 如果沒有約束其高度,則會使用PreferredSizeWidget指定的高度
class CustomAppbar extends StatefulWidget implements PreferredSizeWidget {
final double contentHeight; //從外部指定高度
Color navigationBarBackgroundColor; //設置導航欄背景的顏色
Widget leadingWidget;
Widget trailingWidget;
String title;
CustomAppbar({
@required this.leadingWidget,
@required this.title,
this.contentHeight = 44,
this.navigationBarBackgroundColor = Colors.white,
this.trailingWidget,
}) : super();
@override
State<StatefulWidget> createState() {
return new _CustomAppbarState();
}
@override
Size get preferredSize => new Size.fromHeight(contentHeight);
}
/// 這里沒有直接用SafeArea,而是用Container包裝了一層
/// 因為直接用SafeArea,會把頂部的statusBar區(qū)域留出空白
/// 外層Container會填充SafeArea,指定外層Container背景色也會覆蓋原來SafeArea的顏色
/// var statusheight = MediaQuery.of(context).padding.top; 獲取狀態(tài)欄高度
class _CustomAppbarState extends State<CustomAppbar> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return new Container(
color: widget.navigationBarBackgroundColor,
child: new SafeArea(
top: true,
child: new Container(
decoration: new UnderlineTabIndicator(
borderSide: BorderSide(width: 1.0, color: Color(0xFFeeeeee)),
),
height: widget.contentHeight,
child: new Stack(
alignment: Alignment.center,
children: <Widget>[
Positioned(
left: 0,
child: new Container(
padding: const EdgeInsets.only(left: 5),
child: widget.leadingWidget,
),
),
new Container(
child: new Text(widget.title,
style: new TextStyle(
fontSize: 17, color: Color(0xFF333333))),
),
Positioned(
right: 0,
child: new Container(
padding: const EdgeInsets.only(right: 5),
child: widget.trailingWidget,
),
),
],
)),
),
);
}
}
引用的地方:
appBar: new CustomAppbar(
title: '日歷',
leadingWidget: leftBarButtonItemWidget(),
trailingWidget: rightBarButtonItemsWidget(),
)
leftBarButtonItemWidget()
rightBarButtonItemsWidget()
兩個方法是我自定義的導航欄按鈕,實現(xiàn)自己需要的即可。值得說的是,可以將leadingWidget設置為非@required的,在自定義的AppBar里面做好處理即可,另外在上面的代碼中并沒有限制導航欄上每個Widget所占用的最大空間,如果你的導航欄子組件可能很寬,提前進行妥善處理是個好主意。