首先感谢B站 王叔不秃 在他那里能学到很多
对于很多才接触Flutter的同学在面对精确坐标布局的时候无从下手,误以为flutter做不到或者很难办到,接下来笔者带大家走出这样的困境。
要想获取Widget的大小和位置信息可以通过GlobalKey方法,举一个例子。
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class GlobalKeyTest extends StatelessWidget {
@override
Widget build(BuildContext context) {
GlobalKey globalKey = GlobalKey();
return Scaffold(
appBar: AppBar(
title: Text('GlobalKeyTest'),
),
body: Stack(
children: <Widget>[
Positioned(
left: 100,
top: 0,
child: FlatButton(
key: globalKey,
onPressed: () {
RenderBox renderBox =
globalKey.currentContext.findRenderObject();
print(
'W:${globalKey.currentContext.size.height}H:${globalKey.currentContext.size.width}');
print(
'x:${renderBox.localToGlobal(Offset.zero).dx}y:${renderBox.localToGlobal(Offset.zero).dy}');
},
child: Text("扁平按钮"),
color: Colors.blue,
textColor: Colors.black,
shape: RoundedRectangleBorder(
side: BorderSide(
color: Colors.white,
width: 1,
),
borderRadius: BorderRadius.circular(8)),
),
),
],
),
);
}
}
可以发现点击的时候打印了位置信息和大小信息
I/flutter ( 9984): W:48.0H:88.0
I/flutter ( 9984): x:100.0y:80.0
确实在实战开发中很多情况只是拿到坐标信息是没有用的,比如你需要做自己做一个组件它接受一个Weidget数组进行斜布局,那么只获取位置大小信息是不够的,我们该怎么做呢?实现效果
我们可以利用Stack或者CustomMultiChildLayout做,为了让大家更容易理解我这里就用Stack实现。
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class BevelAbgle extends StatefulWidget {
final List<Widget> myChildren;
BevelAbgle(this.myChildren);
@override
_BevelAbgleState createState() => _BevelAbgleState();
}
class _BevelAbgleState extends State<BevelAbgle> {
final List<GlobalKey> globalKeys = [];
final List<Widget> showChildren = [];
bool show = false;
List<Widget> getCustomChildren() {
List<Widget> myChildren = [];
for (var j = 0; j < widget.myChildren.length; j++) {
var globalKey = GlobalKey();
globalKeys.add(globalKey);
myChildren.add(
Row(
key: globalKey,
mainAxisSize: MainAxisSize.min,
children: <Widget>[widget.myChildren[j]],
),
);
}
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
updateWeight();
setState(() {
show = true;
});
});
return myChildren;
}
void updateWeight() {
var widgetW = 0.0;
var widgetH = 0.0;
for (var i = 0; i < widget.myChildren.length; i++) {
if (i > 0) {
widgetW = widgetW + globalKeys[i - 1].currentContext.size.width;
widgetH = widgetH + globalKeys[i - 1].currentContext.size.height;
}
showChildren.add(Positioned(
left: widgetW,
top: widgetH,
child: widget.myChildren[i],
));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
color: Colors.green,
child: Stack(
children: !show ? getCustomChildren() : showChildren,
),
),
);
}
}
这段代码的思路为:
1.建立一个GlobalKey数组对传递进来的Widget数组提前进行渲染知道并且都赋予GlobalKey保存到数组里。
2.对GlobalKey数组进行循环遍历然后拿到Width和Height进行重新排列绘制。
接下来我们来测试
import 'package:flutter/cupertino.dart';
import 'package:flutter_animation/component/BevelAngle.dart';
class BelevelAnglePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
child: BevelAbgle([
Text('牛'),
Image.network(
'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fwww.gb324.com%2Fd%2Ffile%2Ftitlepic%2F2021-02-17%2F12%2F12044314839.png&refer=http%3A%2F%2Fwww.gb324.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1616221584&t=6b8f7f1c007d07bf98c03cfc3b6e0523',
width: 150,
height: 150,
),
Text('气'),
Image.network(
'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fwww.gb324.com%2Fd%2Ffile%2Ftitlepic%2F2021-02-17%2F12%2F12044314839.png&refer=http%3A%2F%2Fwww.gb324.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1616221584&t=6b8f7f1c007d07bf98c03cfc3b6e0523',
width: 50,
height: 50,
),
Text('冲13333444423211'),
Text('冲13333444423211'),
Image.network(
'https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fwww.gb324.com%2Fd%2Ffile%2Ftitlepic%2F2021-02-17%2F12%2F12044314839.png&refer=http%3A%2F%2Fwww.gb324.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1616221584&t=6b8f7f1c007d07bf98c03cfc3b6e0523',
width: 50,
height: 50,
),
Text('天'),
]),
);
}
}
现在相信你对自定义布局有所了解了。