Layout

Resizable

A box which children can be resized along either the horizontal or vertical axis.

1class ResizableExample extends StatelessWidget {
2 @override
3 Widget build(BuildContext context) => DecoratedBox(
4 decoration: BoxDecoration(
5 border: .all(color: context.theme.colors.border),
6 borderRadius: .circular(8),
7 ),
8 child: FResizable(
9 axis: .vertical,
10 crossAxisExtent: 300,
11 children: [
12 .fixed(
13 extent: 200,
14 minExtent: 100,
15 builder: (_, data, _) =>
16 Label(data: data, icon: FLucideIcons.sunrise, label: 'Morning'),
17 ),
18 .flex(
19 builder: (_, data, _) =>
20 Label(data: data, icon: FLucideIcons.sun, label: 'Afternoon'),
21 ),
22 .flex(
23 flex: 2,
24 builder: (_, data, _) =>
25 Label(data: data, icon: FLucideIcons.sunset, label: 'Evening'),
26 ),
27 ],
28 ),
29 );
30}
31
32class Label extends StatelessWidget {
33 static final format = DateFormat.jm();
34 final FResizableRegionData data;
35 final IconData icon;
36 final String label;
37 const Label({
38 required this.data,
39 required this.icon,
40 required this.label,
41 super.key,
42 });
43 @override
44 Widget build(BuildContext context) {
45 final FThemeData(:colors, :typography) = context.theme;
46 final start = DateTime.fromMillisecondsSinceEpoch(
47 (data.offsetPercentage.min * Duration.millisecondsPerDay).round(),
48 isUtc: true,
49 );
50 final end = DateTime.fromMillisecondsSinceEpoch(
51 (data.offsetPercentage.max * Duration.millisecondsPerDay).round(),
52 isUtc: true,
53 );
54 return Align(
55 child: Column(
56 mainAxisAlignment: .center,
57 children: [
58 Row(
59 mainAxisSize: .min,
60 mainAxisAlignment: .center,
61 children: [
62 Icon(icon, size: 15, color: colors.foreground),
63 const SizedBox(width: 3),
64 Text(
65 label,
66 style: typography.body.sm.copyWith(color: colors.foreground),
67 ),
68 ],
69 ),
70 const SizedBox(height: 5),
71 Text(
72 '${format.format(start)} - ${format.format(end)}',
73 style: typography.body.sm.copyWith(color: colors.foreground),
74 ),
75 ],
76 ),
77 );
78 }
79}
80

CLI

To generate a specific style for customization:

dart run forui style create resizables

Usage

FResizable(...)

1FResizable(
2 style: const .context(),
3 axis: .vertical,
4 divider: .dividerWithThumb,
5 children: [
6 .fixed(
7 extent: 200,
8 minExtent: 100,
9 builder: (context, data, child) => child!,
10 ),
11 .flex(flex: 2, minFlex: 1, builder: (context, data, child) => child!),
12 ],
13)

FResizableRegion.fixed(...)

1FResizableRegion.fixed(
2 extent: 200,
3 minExtent: 100,
4 builder: (context, data, child) => child!,
5 child: const Placeholder(),
6)

FResizableRegion.flex(...)

1FResizableRegion.flex(
2 flex: 2,
3 minFlex: 1,
4 builder: (context, data, child) => child!,
5 child: const Placeholder(),
6)

Examples

Without Cascading

1class NoCascadingResizableExample extends StatelessWidget {
2 @override
3 Widget build(BuildContext context) => DecoratedBox(
4 decoration: BoxDecoration(
5 border: .all(color: context.theme.colors.border),
6 borderRadius: .circular(8),
7 ),
8 child: FResizable(
9 control: const .managed(),
10 axis: .vertical,
11 crossAxisExtent: 300,
12 children: [
13 .fixed(
14 extent: 200,
15 minExtent: 100,
16 builder: (_, data, _) =>
17 Label(data: data, icon: FLucideIcons.sunrise, label: 'Morning'),
18 ),
19 .fixed(
20 extent: 200,
21 minExtent: 100,
22 builder: (_, data, _) =>
23 Label(data: data, icon: FLucideIcons.sun, label: 'Afternoon'),
24 ),
25 .fixed(
26 extent: 200,
27 minExtent: 100,
28 builder: (_, data, _) =>
29 Label(data: data, icon: FLucideIcons.sunset, label: 'Evening'),
30 ),
31 ],
32 ),
33 );
34}
35
36class Label extends StatelessWidget {
37 static final format = DateFormat.jm();
38 final FResizableRegionData data;
39 final IconData icon;
40 final String label;
41 const Label({
42 required this.data,
43 required this.icon,
44 required this.label,
45 super.key,
46 });
47 @override
48 Widget build(BuildContext context) {
49 final FThemeData(:colors, :typography) = context.theme;
50 final start = DateTime.fromMillisecondsSinceEpoch(
51 (data.offsetPercentage.min * Duration.millisecondsPerDay).round(),
52 isUtc: true,
53 );
54 final end = DateTime.fromMillisecondsSinceEpoch(
55 (data.offsetPercentage.max * Duration.millisecondsPerDay).round(),
56 isUtc: true,
57 );
58 return Align(
59 child: Column(
60 mainAxisAlignment: .center,
61 children: [
62 Row(
63 mainAxisSize: .min,
64 mainAxisAlignment: .center,
65 children: [
66 Icon(icon, size: 15, color: colors.foreground),
67 const SizedBox(width: 3),
68 Text(
69 label,
70 style: typography.body.sm.copyWith(color: colors.foreground),
71 ),
72 ],
73 ),
74 const SizedBox(height: 5),
75 Text(
76 '${format.format(start)} - ${format.format(end)}',
77 style: typography.body.sm.copyWith(color: colors.foreground),
78 ),
79 ],
80 ),
81 );
82 }
83}
84

Horizontal

1@override
2Widget build(BuildContext context) => DecoratedBox(
3 decoration: BoxDecoration(
4 border: .all(color: context.theme.colors.border),
5 borderRadius: .circular(8),
6 ),
7 child: FResizable(
8 axis: .horizontal,
9 crossAxisExtent: 300,
10 children: [
11 .fixed(
12 extent: 100,
13 minExtent: 100,
14 builder: (context, data, _) => Align(
15 child: Text('Sidebar', style: context.theme.typography.body.sm),
16 ),
17 ),
18 .fixed(
19 extent: 300,
20 minExtent: 100,
21 builder: (context, data, _) => Align(
22 child: Text('Content', style: context.theme.typography.body.sm),
23 ),
24 ),
25 ],
26 ),
27);
28

Divider with No Thumb

1@override
2Widget build(BuildContext context) => DecoratedBox(
3 decoration: BoxDecoration(
4 border: .all(color: context.theme.colors.border),
5 borderRadius: .circular(8),
6 ),
7 child: FResizable(
8 axis: .horizontal,
9 divider: .divider,
10 crossAxisExtent: 300,
11 children: [
12 .fixed(
13 extent: 100,
14 minExtent: 100,
15 builder: (context, data, _) => Align(
16 child: Text('Sidebar', style: context.theme.typography.body.sm),
17 ),
18 ),
19 .fixed(
20 extent: 300,
21 minExtent: 100,
22 builder: (context, data, _) => Align(
23 child: Text('Content', style: context.theme.typography.body.sm),
24 ),
25 ),
26 ],
27 ),
28);
29

Without Divider

1@override
2Widget build(BuildContext context) => DecoratedBox(
3 decoration: BoxDecoration(
4 border: .all(color: context.theme.colors.border),
5 borderRadius: .circular(8),
6 ),
7 child: FResizable(
8 axis: .horizontal,
9 divider: .none,
10 crossAxisExtent: 300,
11 children: [
12 .fixed(
13 extent: 100,
14 minExtent: 100,
15 builder: (context, data, _) => Align(
16 child: Text('Sidebar', style: context.theme.typography.body.sm),
17 ),
18 ),
19 .fixed(
20 extent: 300,
21 minExtent: 100,
22 builder: (context, data, _) => Align(
23 child: Text('Content', style: context.theme.typography.body.sm),
24 ),
25 ),
26 ],
27 ),
28);
29

On this page