一、認識元件
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 未允禁轉
我的公眾號:程式設計之王
聯絡我--郵箱:1981462002@qq.com --微信:zdl1994328
~ END ~