在某些需求下,咱们须要获取Widget
的大小或位置信息。但Widget
对象自己没有大小及位置数据,那么想要拿到Widget
的大小及位置信息,就须要经过与Widget
对象相关联的RenderBox
对象来获取。app
下面就开始来获取Widget
的大小与位置。ide
要想获取RenderBox
对象,其实很简单。只须要调用BuildContext
的findRenderObject
方法便可。代码以下。flex
//context是一个BuildContext对象
RenderBox renderBox = context.findRenderObject();
复制代码
但有时候,并不能顺利的拿到BuildContext
对象,那该怎么办尼?这时候就须要给Widget
对象设置一个Key,而后根据这个Key来拿到BuildContext
对象,从而获取RenderBox
对象,代码以下。ui
class MyHomePageState extends State<MyHomePage> {
//定义一个key
GlobalKey _key = GlobalKey();
_getRenderBox() {
//获取`RenderBox`对象
RenderBox renderBox = _key.currentContext.findRenderObject();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
children: <Widget>[
Flexible(
flex: 2,
child: Container(
//设置key
key: _key,
color: Colors.red,
),
),
],
),
);
}
}
复制代码
但在使用的时候,咱们会发现若是在initState
方法经过上面的代码来获取RenderBox
对象是不会成功且报错的。这是为何尼?其实在调用initState
方法时,Widget
还未完成渲染,也就不能获取RenderBox
对象。这时候只须要等待Widget
渲染完毕便可。代码以下。spa
class MyHomePageState extends State<MyHomePage> {
@override
void initState() {
//监听Widget是否绘制完毕
WidgetsBinding.instance.addPostFrameCallback(_getRenderBox);
super.initState();
}
//定义一个key
GlobalKey _key = GlobalKey();
_getRenderBox(_) {
//获取`RenderBox`对象
RenderBox renderBox = _key.currentContext.findRenderObject();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Column(
children: <Widget>[
Flexible(
flex: 2,
child: Container(
//设置key
key: _key,
color: Colors.red,
),
),
],
),
);
}
}
复制代码
拿到与Widget
对象相关联的RenderBox
对象来后,就能够很方便的获取Widget
的大小。代码以下。code
Size size = renderBox.size;
复制代码
下面来看一个示例。cdn
class HomeState extends State<HomeWidget> {
@override
void initState() {
//监听Widget是否绘制完毕
WidgetsBinding.instance.addPostFrameCallback(_afterLayout);
super.initState();
}
void _afterLayout(_) {
_getSizes();
}
_getSizes() {
final RenderBox renderBoxRed = _keyRed.currentContext.findRenderObject();
final sizeRed = renderBoxRed.size;
//输出背景为红色的widget的宽高
print("size of red:$sizeRed");
final RenderBox renderBoxBlue = _keyBlue.currentContext.findRenderObject();
final sizeBlue = renderBoxBlue.size;
//输出背景为蓝色的widget的宽高
print("size of Blue:$sizeBlue");
final RenderBox renderBoxAmber =_keyAmber.currentContext.findRenderObject();
final sizeAmber = renderBoxAmber.size;
//输出背景为的widget的宽高
print("size of Amber:$sizeAmber");
}
GlobalKey _keyRed = GlobalKey();
GlobalKey _keyBlue = GlobalKey();
GlobalKey _keyAmber = GlobalKey();
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Flexible(
key: _keyRed,
flex: 1,
child: Container(
color: Colors.red,
),
),
Flexible(
key: _keyBlue,
child: Container(
color: Colors.blue,
),
flex: 2,
),
Container(
key: _keyAmber,
width: 300,
height: 200,
color: Colors.amber,
),
],
);
}
}
复制代码
运行上面代码就能够把Widget
的宽高获取到,输出信息以下。对象
size of red:Size(411.4, 134.5)
size of Blue:Size(411.4, 269.0)
size of Amber:Size(300.0, 200.0)
复制代码
能够发现,获取的宽高都具备设备无关性。blog
获取Widget
的位置跟获取其宽高同样简单,只须要调用不一样API便可。以下。事件
Offset offset = renderBox.localToGlobal(Offset.zero);
复制代码
下面来看一个示例。
class HomeState extends State<HomeWidget> {
@override
void initState() {
//监听Widget是否绘制完毕
WidgetsBinding.instance.addPostFrameCallback(_afterLayout);
super.initState();
}
void _afterLayout(_) {
_getPositions();
}
_getPositions() {
final RenderBox renderBoxRed = _keyRed.currentContext.findRenderObject();
final positionsRed = renderBoxRed.localToGlobal(Offset(0, 0));
print("positions of red:$positionsRed");
final RenderBox renderBoxBlue = _keyBlue.currentContext.findRenderObject();
final positionsBlue = renderBoxBlue.localToGlobal(Offset(0, 0));
print("positions of Blue:$positionsBlue");
final RenderBox renderBoxAmber =
_keyAmber.currentContext.findRenderObject();
final positionsAmber = renderBoxAmber.localToGlobal(Offset(0, 0));
print("positions of Amber:$positionsAmber");
}
GlobalKey _keyRed = GlobalKey();
GlobalKey _keyBlue = GlobalKey();
GlobalKey _keyAmber = GlobalKey();
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Flexible(
key: _keyRed,
flex: 1,
child: Container(
color: Colors.red,
),
),
Flexible(
key: _keyBlue,
child: Container(
color: Colors.blue,
),
flex: 2,
),
//该Widget是居中显示的
Container(
key: _keyAmber,
width: 300,
height: 200,
color: Colors.amber,
),
],
);
}
}
复制代码
运行上面代码就能够把Widget
的位置获取到,输出信息以下。
positions of red:Offset(0.0, 80.0)
positions of Blue:Offset(0.0, 214.5)
positions of Amber:Offset(55.7, 483.4)
复制代码
Flutter
跟Android
同样,都是以屏幕左上方为坐标系的开始位置。而上面的输出信息就是Widget
到坐标系的开始位置的距离。以下图所示。
经过上面的代码,就能够获取到Widget
的大小及位置信息,这在不少时候都是很是有用的。特别是当咱们来本身实现一个自定义Widget
的点击、手势等事件时,就须要跟位置信息来获取事件在Widget
中的位置。
【参考资料】