想要獲取widget的尺寸,必須要等widget的layout結(jié)束之后才能取到,目前有三種方式
- 通過
BuildContext
獲取 - 通過
GlobalKey
獲取 - 通過
SizeChangedLayoutNotifier
獲取
通過BuildContext
獲取
widget的尺寸存在于context?.findRenderObject()?.paintBounds?.size
中,過早獲取可能為空,需要延時獲取.在flutter1.7之前duration
=Duration()
就能獲取到,但是1.7之后必須要設(shè)置一百毫秒以上才行.
class FindSizeWidget extends StatefulWidget {
@override
_FindSizeWidgetState createState() => _FindSizeWidgetState();
}
class _FindSizeWidgetState extends State<FindSizeWidget> {
@override
Widget build(BuildContext context) {
/// 延時一下,需要等state layout結(jié)束之后才能獲取size
Future.delayed(Duration(milliseconds: 100), () {
_printSize();
});
return _buildContentWidget();
}
Widget _buildContentWidget(){
return Container(
color: Colors.red,
child: Text(
'''
1 ... 1
2 ... 2
3 ... 3
4 ... 4
''',
style: TextStyle(fontSize: 30),
maxLines: null,
softWrap: true,
),
);
}
_printSize(){
if (!mounted) return;
var size = context?.findRenderObject()?.paintBounds?.size;
print(size.toString());
}
}
打印結(jié)果:
flutter: Size(277.0, 180.0)
通過GlobalKey
獲取
給FindSizeWidget
增加構(gòu)造方法,通過外部傳入GlobalKey
,方便以后尋找到FindSizeWidget.context
對象.
class FindSizeWidget extends StatefulWidget {
const FindSizeWidget({Key key}) : super(key:key);
}
注意一個
GlobalKey
只能對應(yīng)一個widget對象,當心復用問題.
增加一個獲取尺寸的按鈕.點擊之后獲取尺寸.
class _MyApp extends State<MyApp> {
GlobalKey _globalKey = GlobalKey();
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
FlatButton(
onPressed: () {
var size = _globalKey.currentContext
?.findRenderObject()
?.paintBounds
?.size;
print(size.toString());
},
child: Text("獲取尺寸")),
FindSizeWidget(
key: _globalKey,
)
],
);
}
}
打印結(jié)果:
flutter: Size(277.0, 180.0)
通過SizeChangedLayoutNotifier
獲取
使用SizeChangedLayoutNotifier
方式,Widget會在layout結(jié)束之后會發(fā)出一個LayoutChangedNotification
通知,我們只需要接收這個通知,即可獲取尺寸信息,但是SizeChangedLayoutNotifier
的RenderObject
是_RenderSizeChangedWithCallback
類,它在第一次布局完成之后并不會發(fā)出通知,所以我們要自定義SizeChangedLayoutNotifier
和_RenderSizeChangedWithCallback
兩個類.
_RenderSizeChangedWithCallback
源碼部分:
@override
void performLayout() {
super.performLayout();
// Don't send the initial notification, or this will be SizeObserver all
// over again!
if (_oldSize != null && size != _oldSize)
onLayoutChangedCallback();
_oldSize = size;
}
修改_RenderSizeChangedWithCallback
,只需要去掉_oldSize != null
的判斷即可.
@override
void performLayout() {
super.performLayout();
// Don't send the initial notification, or this will be SizeObserver all
// over again!
if (size != _oldSize)
onLayoutChangedCallback();
_oldSize = size;
}
再修改_FindSizeWidgetState
的build
方法:
@override
Widget build(BuildContext context) {
return NotificationListener<LayoutChangedNotification>(
onNotification: (notification) {
/// 收到布局結(jié)束通知,打印尺寸
_printSize();
/// flutter1.7之后需要返回值,之前是不需要的.
return null;
},
child: CustomSizeChangedLayoutNotifier(
child: _buildContentWidget(),
),
);
}
打印結(jié)果:
flutter: Size(277.0, 180.0)