Foundation

Point Portal

A "floating" portal anchored at a specific point within a child widget's coordinate space.

This widget is typically used to create other high-level widgets, e.g., context menu. You should prefer those high-level widgets unless you're creating a custom widget.

1class PointPortalExample extends StatefulWidget {
2 @override
3 State<PointPortalExample> createState() => _State();
4}
5
6class _State extends State<PointPortalExample> {
7 final _controller = OverlayPortalController();
8 Offset _point = const Offset(75, 50);
9
10 @override
11 Widget build(BuildContext context) => FPointPortal(
12 control: .managed(controller: _controller),
13 point: _point,
14 padding: const .all(5),
15 portalBuilder: (context, _) => Container(
16 decoration: BoxDecoration(
17 color: context.theme.colors.background,
18 border: .all(color: context.theme.colors.border),
19 borderRadius: .circular(4),
20 ),
21 padding: const .only(left: 20, top: 14, right: 20, bottom: 10),
22 child: SizedBox(
23 width: 288,
24 child: Column(
25 mainAxisSize: .min,
26 crossAxisAlignment: .start,
27 children: [
28 Text('Dimensions', style: context.theme.typography.body.md),
29 const SizedBox(height: 7),
30 Text(
31 'Set the dimensions for the layer.',
32 style: context.theme.typography.body.sm.copyWith(
33 color: context.theme.colors.mutedForeground,
34 fontWeight: FontWeight.w300,
35 ),
36 ),
37 const SizedBox(height: 15),
38 for (final (label, value) in [
39 ('Width', '100%'),
40 ('Max. Width', '300px'),
41 ]) ...[
42 Row(
43 children: [
44 Expanded(
45 child: Text(label, style: context.theme.typography.body.sm),
46 ),
47 Expanded(
48 flex: 2,
49 child: FTextField(
50 control: .managed(initial: TextEditingValue(text: value)),
51 ),
52 ),
53 ],
54 ),
55 const SizedBox(height: 7),
56 ],
57 ],
58 ),
59 ),
60 ),
61 child: GestureDetector(
62 onTapDown: (d) {
63 setState(() => _point = d.localPosition);
64 _controller.show();
65 },
66 child: Container(
67 width: 300,
68 height: 150,
69 decoration: BoxDecoration(
70 color: context.theme.colors.muted,
71 borderRadius: .circular(4),
72 ),
73 alignment: .center,
74 child: Text('Tap anywhere', style: context.theme.typography.body.sm),
75 ),
76 ),
77 );
78}
79

Usage

FPointPortal(...)

1FPointPortal(
2 point: const Offset(100, 100),
3 portalBuilder: (context, controller) => const Text('Portal content'),
4 builder: (context, controller, child) => child!,
5 child: const Text('Child'),
6 barrier: null,
7)

On this page