如何 align/render 围绕单个小部件摆动小部件?
How to align/render flutter widgets around a single widget?
基本上这就是我要实现的目标
带有红色 X 的小部件是 根 小部件,所有小部件都需要围绕它构建
这里的所有小部件都将 'rendered' 动态 这意味着我从某个地方获取它们的信息,所以实现这个我想到了两个选择:
- 使用 Stack 小部件或另一个我还没有找到的神秘布局小部件
- 使用简单的列和行,这会产生问题:
这是我正在使用的代码
Widget panelWidget(Panel panel) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
//WIDGETS ON THE LEFT
...panel.attachedPanels
.where((element) => element.attachedToSide == 3)
.map(
(e) => Container(
height: getH(e.panelHeight),
width: getW(e.panelWidth),
decoration:
BoxDecoration(border: Border.all(color: Colors.black)),
),
)
.toList(),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
//WIDGETS ON TOP
...panel.attachedPanels
.where((element) => element.attachedToSide == 2)
.map(
(e) => Container(
height: getH(e.panelHeight),
width: getW(e.panelWidth),
decoration:
BoxDecoration(border: Border.all(color: Colors.black)),
),
)
.toList(),
Center( //THIS IS THE ROOT WIDGET
child: Container(
height: getH(panel.panelHeight),
width: getW(panel.panelWidth),
decoration:
BoxDecoration(border: Border.all(color: Colors.black)),
),
),
//WIDGETS ON THE BOTTOM
...panel.attachedPanels
.where((element) => element.attachedToSide == 0)
.map(
(e) => Container(
height: getH(e.panelHeight),
width: getW(e.panelWidth),
decoration:
BoxDecoration(border: Border.all(color: Colors.black)),
),
)
.toList(),
],
),
//WIDGETS ON THE RITGHT
...panel.attachedPanels
.where((element) => element.attachedToSide == 1)
.map(
(e) => Container(
height: getH(e.panelHeight),
width: getW(e.panelWidth),
decoration:
BoxDecoration(border: Border.all(color: Colors.black)),
),
)
.toList(),
],
);
}
请注意逻辑,因为我现在专注于首先解决这个问题,您可以在下面看到根小部件的注释,并且从 4 个侧面围绕它有我需要渲染的小部件列表,在纸上看起来不错,但这是输出,我使用的是 Flutter Web:
如您所见,左右小部件未与根小部件对齐,因为它们遵循行的交叉轴对齐方式。
Flutter 的工作是将这两个小部件放在中心,但是小部件的大小不同,因此会稍微移动整个小部件树的中心点,我尝试了不同的组合,但它们都没有用,任何帮助非常欢迎
使用 Table
小部件,它可以为您完成您想做的事情。
不要考虑在另一个“根”小部件旁边构建一个小部件。从树的角度思考一切,其中一切都具有 parent-child/children 关系。您的每个小部件在树中都处于同一级别,它们只需要正确的父级将它们放在正确的位置。
您在 Table
中使用 Placeholder
所需的布局在以下代码中实现。可以复制粘贴到 DartPad 中。
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Table(
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
children: <TableRow>[
TableRow(
children: <Widget>[
const SizedBox(),
SizedBox(
height: 100,
child: Placeholder(color: Colors.white),
),
const SizedBox(),
],
),
TableRow(
children: <Widget>[
SizedBox(
height: 100,
child: Placeholder(color: Colors.white),
),
SizedBox(
height: 100,
child: Placeholder(color: Colors.white),
),
SizedBox(
height: 100,
child: Placeholder(color: Colors.white),
),
],
),
TableRow(
children: <Widget>[
const SizedBox(),
SizedBox(
height: 100,
child: Placeholder(color: Colors.white),
),
const SizedBox(),
],
),
],
);
}
}
结果:
为了适应“动态”布局,对上述代码的更改微不足道。以下调整 MyWidget
以采用可选的顶部、底部、左侧和右侧小部件,并相应地调整所有内容,以便 Table
正常工作。
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(
root: SizedBox(
height: 100,
child: Placeholder(color: Colors.white),
),
top: SizedBox(
height: 100,
child: Placeholder(color: Colors.white),
),
right: SizedBox(
height: 100,
child: Placeholder(color: Colors.white),
),
),
),
),
);
}
}
class MyWidget extends StatelessWidget {
final Widget root;
final Widget? right, left, top, bottom;
const MyWidget({
required this.root,
this.right,
this.left,
this.top,
this.bottom,
});
@override
Widget build(BuildContext context) {
final List<Widget> middleRow = [
if(left != null)
left!,
root,
if(right != null)
right!,
];
final List<Widget> topRow = [
if(left != null)
const SizedBox(),
top ?? const SizedBox(),
if(right != null)
const SizedBox(),
];
final List<Widget> bottomRow = [
if(left != null)
const SizedBox(),
bottom ?? const SizedBox(),
if(right != null)
const SizedBox(),
];
return Table(
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
children: <TableRow>[
TableRow(
children: topRow,
),
TableRow(
children: middleRow,
),
TableRow(
children: bottomRow,
),
],
);
}
}
或者,如果您想要空 space,其中省略了小部件:
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(
root: SizedBox(
height: 100,
child: Placeholder(color: Colors.white),
),
top: SizedBox(
height: 100,
child: Placeholder(color: Colors.white),
),
right: SizedBox(
height: 100,
child: Placeholder(color: Colors.white),
),
),
),
),
);
}
}
class MyWidget extends StatelessWidget {
final Widget root;
final Widget? right, left, top, bottom;
const MyWidget({
required this.root,
this.right,
this.left,
this.top,
this.bottom,
});
@override
Widget build(BuildContext context) {
final List<Widget> middleRow = [
left ?? const SizedBox(),
root,
right ?? const SizedBox(),
];
final List<Widget> topRow = [
const SizedBox(),
top ?? const SizedBox(),
const SizedBox(),
];
final List<Widget> bottomRow = [
const SizedBox(),
bottom ?? const SizedBox(),
const SizedBox(),
];
return Table(
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
children: <TableRow>[
TableRow(
children: topRow,
),
TableRow(
children: middleRow,
),
TableRow(
children: bottomRow,
),
],
);
}
}
基本上这就是我要实现的目标
带有红色 X 的小部件是 根 小部件,所有小部件都需要围绕它构建
这里的所有小部件都将 'rendered' 动态 这意味着我从某个地方获取它们的信息,所以实现这个我想到了两个选择:
- 使用 Stack 小部件或另一个我还没有找到的神秘布局小部件
- 使用简单的列和行,这会产生问题: 这是我正在使用的代码
Widget panelWidget(Panel panel) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
//WIDGETS ON THE LEFT
...panel.attachedPanels
.where((element) => element.attachedToSide == 3)
.map(
(e) => Container(
height: getH(e.panelHeight),
width: getW(e.panelWidth),
decoration:
BoxDecoration(border: Border.all(color: Colors.black)),
),
)
.toList(),
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
//WIDGETS ON TOP
...panel.attachedPanels
.where((element) => element.attachedToSide == 2)
.map(
(e) => Container(
height: getH(e.panelHeight),
width: getW(e.panelWidth),
decoration:
BoxDecoration(border: Border.all(color: Colors.black)),
),
)
.toList(),
Center( //THIS IS THE ROOT WIDGET
child: Container(
height: getH(panel.panelHeight),
width: getW(panel.panelWidth),
decoration:
BoxDecoration(border: Border.all(color: Colors.black)),
),
),
//WIDGETS ON THE BOTTOM
...panel.attachedPanels
.where((element) => element.attachedToSide == 0)
.map(
(e) => Container(
height: getH(e.panelHeight),
width: getW(e.panelWidth),
decoration:
BoxDecoration(border: Border.all(color: Colors.black)),
),
)
.toList(),
],
),
//WIDGETS ON THE RITGHT
...panel.attachedPanels
.where((element) => element.attachedToSide == 1)
.map(
(e) => Container(
height: getH(e.panelHeight),
width: getW(e.panelWidth),
decoration:
BoxDecoration(border: Border.all(color: Colors.black)),
),
)
.toList(),
],
);
}
请注意逻辑,因为我现在专注于首先解决这个问题,您可以在下面看到根小部件的注释,并且从 4 个侧面围绕它有我需要渲染的小部件列表,在纸上看起来不错,但这是输出,我使用的是 Flutter Web:
如您所见,左右小部件未与根小部件对齐,因为它们遵循行的交叉轴对齐方式。 Flutter 的工作是将这两个小部件放在中心,但是小部件的大小不同,因此会稍微移动整个小部件树的中心点,我尝试了不同的组合,但它们都没有用,任何帮助非常欢迎
使用 Table
小部件,它可以为您完成您想做的事情。
不要考虑在另一个“根”小部件旁边构建一个小部件。从树的角度思考一切,其中一切都具有 parent-child/children 关系。您的每个小部件在树中都处于同一级别,它们只需要正确的父级将它们放在正确的位置。
您在 Table
中使用 Placeholder
所需的布局在以下代码中实现。可以复制粘贴到 DartPad 中。
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(),
),
),
);
}
}
class MyWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Table(
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
children: <TableRow>[
TableRow(
children: <Widget>[
const SizedBox(),
SizedBox(
height: 100,
child: Placeholder(color: Colors.white),
),
const SizedBox(),
],
),
TableRow(
children: <Widget>[
SizedBox(
height: 100,
child: Placeholder(color: Colors.white),
),
SizedBox(
height: 100,
child: Placeholder(color: Colors.white),
),
SizedBox(
height: 100,
child: Placeholder(color: Colors.white),
),
],
),
TableRow(
children: <Widget>[
const SizedBox(),
SizedBox(
height: 100,
child: Placeholder(color: Colors.white),
),
const SizedBox(),
],
),
],
);
}
}
结果:
为了适应“动态”布局,对上述代码的更改微不足道。以下调整 MyWidget
以采用可选的顶部、底部、左侧和右侧小部件,并相应地调整所有内容,以便 Table
正常工作。
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(
root: SizedBox(
height: 100,
child: Placeholder(color: Colors.white),
),
top: SizedBox(
height: 100,
child: Placeholder(color: Colors.white),
),
right: SizedBox(
height: 100,
child: Placeholder(color: Colors.white),
),
),
),
),
);
}
}
class MyWidget extends StatelessWidget {
final Widget root;
final Widget? right, left, top, bottom;
const MyWidget({
required this.root,
this.right,
this.left,
this.top,
this.bottom,
});
@override
Widget build(BuildContext context) {
final List<Widget> middleRow = [
if(left != null)
left!,
root,
if(right != null)
right!,
];
final List<Widget> topRow = [
if(left != null)
const SizedBox(),
top ?? const SizedBox(),
if(right != null)
const SizedBox(),
];
final List<Widget> bottomRow = [
if(left != null)
const SizedBox(),
bottom ?? const SizedBox(),
if(right != null)
const SizedBox(),
];
return Table(
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
children: <TableRow>[
TableRow(
children: topRow,
),
TableRow(
children: middleRow,
),
TableRow(
children: bottomRow,
),
],
);
}
}
或者,如果您想要空 space,其中省略了小部件:
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: MyWidget(
root: SizedBox(
height: 100,
child: Placeholder(color: Colors.white),
),
top: SizedBox(
height: 100,
child: Placeholder(color: Colors.white),
),
right: SizedBox(
height: 100,
child: Placeholder(color: Colors.white),
),
),
),
),
);
}
}
class MyWidget extends StatelessWidget {
final Widget root;
final Widget? right, left, top, bottom;
const MyWidget({
required this.root,
this.right,
this.left,
this.top,
this.bottom,
});
@override
Widget build(BuildContext context) {
final List<Widget> middleRow = [
left ?? const SizedBox(),
root,
right ?? const SizedBox(),
];
final List<Widget> topRow = [
const SizedBox(),
top ?? const SizedBox(),
const SizedBox(),
];
final List<Widget> bottomRow = [
const SizedBox(),
bottom ?? const SizedBox(),
const SizedBox(),
];
return Table(
defaultVerticalAlignment: TableCellVerticalAlignment.middle,
children: <TableRow>[
TableRow(
children: topRow,
),
TableRow(
children: middleRow,
),
TableRow(
children: bottomRow,
),
],
);
}
}