1 LayoutBuilder
作用比较类似css的@media ,根据不同的尺寸渲染不同的节点
LayoutBuilder(
builder:(BuildContext context, constraints) {
print(constraints); // BoxConstraints(0.0<=w<=360.0, 0.0<=h<=692.0)
print(constraints.maxHeight);
print(constraints.minHeight);
print(constraints.maxWidth);
print(constraints.minWidth);
return constraints.minWidth>200? Text('big one'): Text('small one');
},
)
The builder function is called in the following situations:
- The first time the widget is laid out. // 初次渲染
- When the parent widget passes different layout constraints. // constraints发生变化
- When the parent widget updates this widget. // 父组件更新
- When the dependencies that the builder function subscribes to change. // builder函数中的依赖(状态等)改变
The builder function is not called during layout if the parent passes the same constraints repeatedly.
2 MediaQuery
根据系统信息,渲染不同的样式,如屏幕尺寸,手机横纵方向....
f the widget only requires a subset of properties of the MediaQueryData object, it is preferred to use the specific methods (for example: MediaQuery.sizeOf and MediaQuery.paddingOf), as those methods will not cause a widget to rebuild when unrelated properties are updated.
MediaQuery.removePadding 去掉安全距离
MediaQuery.removePadding({
Key? key,
required BuildContext context,
bool removeLeft = false,
bool removeTop = false,
bool removeRight = false,
bool removeBottom = false,
required Widget child,
});
MediaQuery.of(context) 从context获取当前系统信息
size: 屏幕尺寸
devicePixelRatio: 屏蔽像素百分比
platformBrightness: 明暗风格(正常模式、黑暗模式)
orientation: 屏幕方向
viewInsets 为键盘弹出时等遮挡屏幕边距,其中 viewInsets.bottom 为键盘高度
3 使用一些组件来自适应布局
FittedBox
类似css 的Object.fit,确定子集的布局方式
FittedBox(fit:ObjectFit.xxx,child:xxx)
AspectRatio
根据宽高比布局
AspectRatio(
aspectRatio: 0.5,
child: Container(
width: 100.0,
height: 50.0,
color: Colors.green,
),
),
-
Flex布局(Expanded+Row等)
不在这里细说
FractionallySizedBox
FractionallySizedBox(
widthFactor: 0.5, // 宽度因子
heightFactor: 0.5, // 高度因子
alignment: FractionalOffset.center, // 排列
child: DecoratedBox(
decoration: BoxDecoration(
border: Border.all(
color: Colors.blue,
width: 4,
),
),
),
),
4 一些响应式布局的widget
CustomSingleChildLayout
(还没用过,没有遇到类似的使用场景)
class CusLayout extends SingleChildLayoutDelegate {
@override
BoxConstraints getConstraintsForChild(BoxConstraints constraints) {
return super.getConstraintsForChild(constraints);
}
@override
Size getSize(BoxConstraints constraints) {
constraints =constraints *10; // 修改原来的constraints
return super.getSize(constraints);
}
@override
Offset getPositionForChild(Size size, Size childSize) {
// 根据size修改定位
if(xxx){
return Offset(100,100);
}
// return super.getPositionForChild(size, childSize);
return Offset(50,50);
}
@override
bool shouldRelayout(covariant SingleChildLayoutDelegate oldDelegate) {
return false;
}
}
CustomSingleChildLayout(child:xxx,delegate:CusLayout())
CustomMultiChildLayout
类似CustomSingleChildLayout
// 官方示例(比较完整)下边仅仅粘贴个示例
// https://api.flutter-io.cn/flutter/widgets/CustomMultiChildLayout-class.html
class _CascadeLayoutDelegate extends MultiChildLayoutDelegate {
_CascadeLayoutDelegate({
required this.colors,
required this.overlap,
required this.textDirection,
});
final Map<String, Color> colors;
final double overlap;
final TextDirection textDirection;
@override
void performLayout(Size size) {
final double columnWidth = size.width / colors.length;
Offset childPosition = Offset.zero;
switch (textDirection) {
case TextDirection.rtl:
childPosition += Offset(size.width, 0);
case TextDirection.ltr:
break;
}
for (final String color in colors.keys) {
// layoutChild must be called exactly once for each child.
final Size currentSize = layoutChild(
color,
BoxConstraints(maxHeight: size.height, maxWidth: columnWidth),
);
// positionChild must be called to change the position of a child from
// what it was in the previous layout. Each child starts at (0, 0) for the
// first layout.
switch (textDirection) {
case TextDirection.rtl:
positionChild(color, childPosition - Offset(currentSize.width, 0));
childPosition +=
Offset(-currentSize.width, currentSize.height - overlap);
case TextDirection.ltr:
positionChild(color, childPosition);
childPosition +=
Offset(currentSize.width, currentSize.height - overlap);
}
}
}
// shouldRelayout is called to see if the delegate has changed and requires a
// layout to occur. Should only return true if the delegate state itself
// changes: changes in the CustomMultiChildLayout attributes will
// automatically cause a relayout, like any other widget.
@override
bool shouldRelayout(_CascadeLayoutDelegate oldDelegate) {
return oldDelegate.textDirection != textDirection ||
oldDelegate.overlap != overlap;
}
}
CustomMultiChildLayout(
delegate: _CascadeLayoutDelegate(
colors: _colors,
overlap: 30.0,
textDirection: Directionality.of(context),
),
children:xxx)
OrientationBuilder
根据手机横纵向布局
OrientationBuilder(builder(BuildContext context,
Orientation orientation){
if(xxx){
return
}
})