Flutter CustomSingleChildLayout 通用单子布局
Posted 一叶飘舟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Flutter CustomSingleChildLayout 通用单子布局相关的知识,希望对你有一定的参考价值。
一、认识组件
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: CustomSingleChildLayout(
delegate: _TolySingleChildLayoutDelegate(),
child: Container(
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也许可以帮到你。
以上是关于Flutter CustomSingleChildLayout 通用单子布局的主要内容,如果未能解决你的问题,请参考以下文章
[Flutter] flutter项目一直卡在 Running Gradle task 'assembleDebug'...
flutter 日志输出,Flutter打印日志,flutter log,flutter 真机日志
Flutter开发 Flutter 包和插件 ( Flutter 包和插件简介 | 创建 Flutter 插件 | 创建 Dart 包 )
如何解决flutter gradle build error?C:\flutter\packages\flutter_tools\gradle\flutter.gradle' line: 991