我正在尝试将对话框(例如工具提示、下拉列表或模式)放置在页面上特定元素的旁边。目标是保持对话框相对于元素的位置一致,无论屏幕大小或分辨率如何。
目前,当屏幕尺寸变化时,对话框的位置会发生变化,这会导致与其他元素错位或重叠。我需要一个解决方案,确保对话框保持锚定在目标元素旁边,而不会破坏不同设备上的布局或调整屏幕大小时。
问题: 如何将对话框放置在特定页面元素旁边,使其位置在不同的屏幕尺寸上保持一致?
这是我的代码:
void onActionButtonPressed() {
showDialog(
barrierColor: Colors.transparent,
context: pageContext,
builder: (context) => Align(
alignment: const Alignment(0.52, -0.65),
child: Container(
constraints: const BoxConstraints(maxWidth: 320, maxHeight: 235),
padding: const EdgeInsets.fromLTRB(24, 24, 24, 32),
decoration: BoxDecoration(
color: CustomColors.surface,
borderRadius: BorderRadius.circular(12),
border: Border.all(
width: 1,
color: CustomColors.outline,
)),
child: const Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("TEXT HERE"),
],
),
),
),
);
}
您可以使用 Stack 中的 Positioned 小部件,而不是依赖具有静态对齐值的 Align 小部件。这是修改后的代码
void onActionButtonPressed(BuildContext context) {
RenderBox renderBox = context.findRenderObject() as RenderBox;
Offset offset = renderBox.localToGlobal(Offset.zero);
Size size = renderBox.size;
showDialog(
barrierColor: Colors.transparent,
context: context,
builder: (context) => Stack(
children: [
Positioned(
left: offset.dx,
top: offset.dy + size.height,
child: Material(
color: Colors.transparent,
child: Container(
constraints: const BoxConstraints(maxWidth: 320, maxHeight: 235),
padding: const EdgeInsets.fromLTRB(24, 24, 24, 32),
decoration: BoxDecoration(
color: CustomColors.surface,
borderRadius: BorderRadius.circular(12),
border: Border.all(
width: 1,
color: CustomColors.outline,
),
),
child: const Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("TEXT HERE"),
],
),
),
),
),
],
),
);
}
您可以使用
CompositedTransformTarget
和 CompositedTransformFollower
或 OverLayPortal 为此。这是一个例子
class _SpecificPositionedDialog extends StatefulWidget {
const _SpecificPositionedDialog({super.key});
@override
State<_SpecificPositionedDialog> createState() => _SpecificPositionedDialogState();
}
class _SpecificPositionedDialogState extends State<_SpecificPositionedDialog> {
final LayerLink layerLink = LayerLink();
bool showLink = false;
@override
Widget build(BuildContext context) {
return Column(
children: [
CompositedTransformTarget(
link: layerLink,
child: ElevatedButton(
onPressed: () {
showLink = !showLink;
setState(() {});
},
child: const Text("Show"),
),
),
if (showLink)
CompositedTransformFollower(
link: layerLink,
showWhenUnlinked: false,
targetAnchor: Alignment.bottomCenter,
followerAnchor: Alignment.topCenter,
child: Container(
height: 200,
width: 200,
color: Colors.red.withOpacity(.2),
),
),
],
);
}
}