Flutter如何围绕单个根Widget对齐渲染四周动态生成的组件
解决方案
方案1:改用Stack布局(更推荐动态渲染场景)
Stack天生适合以某个组件为锚点定位其他元素的需求,你可以把根组件放在Stack中心,其余四个方向的组件通过Positioned和根组件的尺寸做偏移计算即可,完全不受其他组件尺寸影响,对齐逻辑更可控:
Widget panelWidget(Panel panel) { final rootWidth = getW(panel.panelWidth); final rootHeight = getH(panel.panelHeight); return Stack( alignment: Alignment.center, clipBehavior: Clip.none, children: [ // 根组件 Container( height: rootHeight, width: rootWidth, decoration: BoxDecoration(border: Border.all(color: Colors.black)), ), // 左侧组件 ...panel.attachedPanels.where((e) => e.attachedToSide == 3).map((e) { final w = getW(e.panelWidth); final h = getH(e.panelHeight); return Positioned( right: rootWidth / 2 + w / 2, // 与根组件纵向居中对齐 top: (rootHeight - h) / 2, child: Container( height: h, width: w, decoration: BoxDecoration(border: Border.all(color: Colors.black)), ), ); }).toList(), // 右侧组件 ...panel.attachedPanels.where((e) => e.attachedToSide == 1).map((e) { final w = getW(e.panelWidth); final h = getH(e.panelHeight); return Positioned( left: rootWidth / 2 + w / 2, top: (rootHeight - h) / 2, child: Container( height: h, width: w, decoration: BoxDecoration(border: Border.all(color: Colors.black)), ), ); }).toList(), // 顶部组件 ...panel.attachedPanels.where((e) => e.attachedToSide == 2).map((e) { final w = getW(e.panelWidth); final h = getH(e.panelHeight); return Positioned( bottom: rootHeight / 2 + h / 2, left: (rootWidth - w) / 2, child: Container( height: h, width: w, decoration: BoxDecoration(border: Border.all(color: Colors.black)), ), ); }).toList(), // 底部组件 ...panel.attachedPanels.where((e) => e.attachedToSide == 0).map((e) { final w = getW(e.panelWidth); final h = getH(e.panelHeight); return Positioned( top: rootHeight / 2 + h / 2, left: (rootWidth - w) / 2, child: Container( height: h, width: w, decoration: BoxDecoration(border: Border.all(color: Colors.black)), ), ); }).toList(), ], ); }
如果同一侧有多个组件,仅需要调整对应方向的偏移累加逻辑即可,比Row+Column的嵌套布局灵活度更高。
方案2:修改现有Row+Column布局修复对齐问题
现有代码的问题根源是:外层Row的crossAxisAlignment: CrossAxisAlignment.center是让左右组件对齐整个Column的纵向中心,但Column的总高度是「顶部组件总高+根组件高度+底部组件总高」,自然和根组件的中心不重合。
可以把左右侧组件各自包裹在Column里,用SizedBox撑出和上下组件等高的占位区域,强制让中间的组件和根对齐:
Widget panelWidget(Panel panel) { // 先计算上下侧组件的总高度 final topTotalHeight = panel.attachedPanels.where((e) => e.attachedToSide == 2).fold<double>(0, (sum, e) => sum + getH(e.panelHeight)); final bottomTotalHeight = panel.attachedPanels.where((e) => e.attachedToSide == 0).fold<double>(0, (sum, e) => sum + getH(e.panelHeight)); return Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ //WIDGETS ON THE LEFT ...panel.attachedPanels .where((element) => element.attachedToSide == 3) .map( (e) => Column( mainAxisSize: MainAxisSize.min, children: [ SizedBox(height: topTotalHeight), Container( height: getH(e.panelHeight), width: getW(e.panelWidth), decoration: BoxDecoration(border: Border.all(color: Colors.black)), ), SizedBox(height: bottomTotalHeight), ], ), ) .toList(), Column( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, 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 RIGHT ...panel.attachedPanels .where((element) => element.attachedToSide == 1) .map( (e) => Column( mainAxisSize: MainAxisSize.min, children: [ SizedBox(height: topTotalHeight), Container( height: getH(e.panelHeight), width: getW(e.panelWidth), decoration: BoxDecoration(border: Border.all(color: Colors.black)), ), SizedBox(height: bottomTotalHeight), ], ), ) .toList(), ], ); }
该方案不需要调整你现有的组件分类逻辑,仅需要给左右组件加一层带占位高度的Column即可修复对齐问题。
内容的提问来源于stack exchange,提问作者Extreme Geek
相关产品推荐
相关产品推荐

