一、认识组件
1. CustomSingleChildLayout组件介绍
可容纳一个子组件,并指定代理类对子组件进行排布。代理类可获取父容器区域和子组件的区域大小,及区域约束情况。
名称: CustomSingleChildLayout 通用单子排布
类型: 布局型
重要性: ☆☆☆
相关组件: 【Align】、【FractionallySizedBox】、【CustomMultiChildLayout】
家族: RenderObjectWidget
|--- SingleChildRenderObjectWidget
|--- CustomSingleChildLayout
复制代码
二、组件测试
1. 测试环境:
这里父容器使用
11灰的300*200的盒子
,子组件为不设宽高的橙色Container
。
如下: 默认的约束条件,会使橙色Container
伸展占满父容器。
class CustomSingleChildLayoutDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: 300,
height: 200,
color: Colors.grey.withAlpha(11),
child:nContainer(
color: Colors.orange,
),
);
}
}
复制代码
2. 认识CustomSingleChildLayout
CustomSingleChildLayout容纳一个child,且需要一个抽象代理类
SingleChildLayoutDelegate
Flutter并没有提供可用的实现类,所以只能自定义_TolySingleChildLayoutDelegate
。
class CustomSingleChildLayoutDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: 300,
height: 200,
color: Colors.grey.withAlpha(11),
child: CustomSingleChildLayout(
delegate: _TolySingleChildLayoutDelegate(),
child: Container(
color: Colors.orange,
),
),
);
}
}
复制代码
SingleChildLayoutDelegate
必须实现shouldRelayout
方法,可重写:Size getSize(BoxConstraints)
: 可获取父容器约束条件Offset getPositionForChild(Size, Size)
可获取父子组件的区域,返回子组件偏移量BoxConstraints getConstraintsForChild(BoxConstraints)
可获取父容器约束条件,并返回新的约束条件
class _TolySingleChildLayoutDelegate extends SingleChildLayoutDelegate {
@override
bool shouldRelayout(SingleChildLayoutDelegate oldDelegate) {
return true;
}
@override
Size getSize(BoxConstraints constraints) {
print('----getSize:----constraints:$constraints----');
return super.getSize(constraints);
}
@override
Offset getPositionForChild(Size size, Size childSize) {
print('----size:$size----childSize:$childSize----');
return super.getPositionForChild(size, childSize);
}
@override
BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
print('----getConstraintsForChild:----constraints:$constraints----');
return super.getConstraintsForChild(constraints);
}
}
复制代码
看一下运行打印结果:
I/flutter (28366): ----getSize:----constraints:BoxConstraints(w=300.0, h=200.0)----
I/flutter (28366): ----getConstraintsForChild:----constraints:BoxConstraints(w=300.0, h=200.0)----
I/flutter (28366): ----size:Size(300.0, 200.0)----childSize:Size(300.0, 200.0)----
复制代码
3.使用新的区域约束
getConstraintsForChild
可以根据原约束区域
返回新的约束区域
。如下:
@override
BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
print('----getConstraintsForChild:----constraints:$constraints----');
return BoxConstraints(
maxHeight: constraints.maxHeight/2,
maxWidth: constraints.maxWidth/2,
minHeight: constraints.maxHeight/4,
minWidth: constraints.maxWidth/4,
);
}
复制代码
4. 子组件的偏移
Offset getPositionForChild(Size, Size)
可获取父、子组件的区域,返回子组件偏移量
如下,在刚才的基础上,可以通过偏移让子组件到容器的右上角。
@override
Offset getPositionForChild(Size size, Size childSize) {
print('----size:$size----childSize:$childSize----');
return Offset(size.width/2,0 );
}
复制代码
三、CustomSingleChildLayout能干嘛?
从上面可以看出,使用
CustomSingleChildLayout
可以获取父组件和子组件的布局区域。并可以对子组件进行盒约束
及偏移定位
。一句话来说用于排布一个组件。
1. 控制偏移的代理类
传入一个
Offset对象
控制子组件的偏移。
class _OffSetDelegate extends SingleChildLayoutDelegate {
final Offset offset;
_OffSetDelegate({this.offset = Offset.zero});
@override
bool shouldRelayout(_OffSetDelegate oldDelegate) =>
offset != oldDelegate.offset;
@override
Offset getPositionForChild(Size size, Size childSize) {
return offset;
}
}
复制代码
2. 封装类OffSetWidget
你可以直接用
CustomSingleChildLayout组件
,但为了方便使用,一般都会进行封装使用
下面的OffSetWidget组件
可以实现子组件相对于父组件的偏移。
class OffSetWidget extends StatelessWidget {
final Offset offset;
final Widget child;
OffSetWidget({this.offset = Offset.zero, this.child});
@override
Widget build(BuildContext context) {
return CustomSingleChildLayout(
delegate: _OffSetDelegate(offset: offset),
child: child,
);
}
}
复制代码
3. OffSetWidget使用
这样就可以让子组件在父组件中发生相对偏移。
简约派代表:"等等...老子看了半天,你给我个简易版的Padding?还花里胡哨的。"
兄台莫急,且往下看。
class OffSetWidgetDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: 300,
height: 100,
alignment: Alignment.topRight,
color: Colors.grey.withAlpha(11),
child: OffSetWidget(
offset: Offset(20, 20),
child: Icon(Icons.android, size: 30,color: Colors.green,),
));
}
}
复制代码
这里最大的优势是:
Offset支持负偏移
child: OffSetWidget(
offset: Offset(-20, 20),
child: Icon(Icons.android, size: 30,color: Colors.green,),
));
复制代码
4. 方向版
通过动态计算,可以锁定访问进行偏移,如下:
这样就像Position的能力,但Position有必须用于Stack的现在。
而OffSetWidget
随意 并且支持负偏移
class OffSetWidget extends StatelessWidget {
final Offset offset;
final Widget child;
final Direction direction;
OffSetWidget({this.offset = Offset.zero,
this.child,
this.direction = Direction.topLeft});
@override
Widget build(BuildContext context) {
return CustomSingleChildLayout(
delegate: _OffSetDelegate(offset: offset, direction: direction),
child: child,
);
}
}
enum Direction { topLeft, topRight, bottomLeft, bottomRight }
class _OffSetDelegate extends SingleChildLayoutDelegate {
final Offset offset;
final Direction direction;
_OffSetDelegate(
{this.offset = Offset.zero, this.direction = Direction.topLeft});
@override
bool shouldRelayout(_OffSetDelegate oldDelegate) =>
offset != oldDelegate.offset;
@override
Offset getPositionForChild(Size size, Size childSize) {
var w = size.width;
var h = size.height;
var wc = childSize.width;
var hc = childSize.height;
switch (direction) {
case Direction.topLeft:
return offset;
case Direction.topRight:
return offset.translate(w - wc - offset.dx * 2, 0);
case Direction.bottomLeft:
return offset.translate(0, h - hc - offset.dy * 2);
case Direction.bottomRight:
return offset.translate(w - wc - offset.dx * 2, h - hc - offset.dy * 2);
}
return offset;
}
}
复制代码
CustomSingleChildLayout
组件的用法还是比较简单的。上面代码只是简单演示一下使用方式,也许并不是太实用。Positioned组件
可以实现定位,SizedOverflowBox组件
可以实现溢出。 不过当你遇到对某一个组件约束或定位困难时,CustomSingleChildLayout
也许可以帮到你。
尾声
欢迎Star和关注FlutterUnit 的发展,让我们一起携手,成为Unit一员。
另外本人有一个Flutter微信交流群,欢迎小伙伴加入,共同分享Flutter的知识,期待与你的交流与切磋。
@张风捷特烈 2020.05.26 未允禁转
我的公众号:编程之王
联系我--邮箱:[email protected] --微信:zdl1994328
~ END ~