Layout
Resizable
A box which children can be resized along either the horizontal or vertical axis.
1class ResizableExample extends StatelessWidget {2 @override3 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}3132class 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 @override44 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}80CLI
To generate a specific style for customization:
dart run forui style create resizablesUsage
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 @override3 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}3536class 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 @override48 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}84Horizontal
1@override2Widget 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);28Divider with No Thumb
1@override2Widget 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);29Without Divider
1@override2Widget 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