|
| 1 | +# Helper Widgets for Making Adaptive Layouts in Flutter (AdaptiveScaffold) |
| 2 | + |
| 3 | +This package contains some helper widgets that make the process of developing adaptive layouts easier, especially with navigational elements. |
| 4 | + |
| 5 | +To see examples of using these helper widgets to make a simple but common adaptive layout: |
| 6 | + |
| 7 | +```bash |
| 8 | +cd example/ |
| 9 | +flutter run --release |
| 10 | +``` |
| 11 | +## AdaptiveScaffold: |
| 12 | +AdaptiveScaffold implements the basic visual layout structure for Material Design 3 that adapts to a variety of screens. It provides a preset of layout, including positions and animations, by handling macro changes in navigational elements and bodies based on the current features of the screen, namely screen width and platform. For example, the navigational elements would be a BottomNavigationBar on a small mobile device and a NavigationRail on larger devices. The body is the primary screen that takes up the space left by the navigational elements. The secondaryBody acts as an option to split the space between two panes for purposes such as having a detail view. There is some automatic functionality with foldables to handle the split between panels properly. AdaptiveScaffold is much simpler to use but is not the best if you would like high customizability. Apps that would like more refined layout and/or animation should use AdaptiveLayout. |
| 13 | +### Example Usage: |
| 14 | + |
| 15 | +<?code-excerpt ...> |
| 16 | +```dart |
| 17 | + AdaptiveScaffold( |
| 18 | + destinations: const [ |
| 19 | + NavigationDestination(icon: Icon(Icons.inbox), label: 'Inbox'), |
| 20 | + NavigationDestination(icon: Icon(Icons.article), label: 'Articles'), |
| 21 | + NavigationDestination(icon: Icon(Icons.chat), label: 'Chat'), |
| 22 | + NavigationDestination(icon: Icon(Icons.video_call), label: 'Video'), |
| 23 | + ], |
| 24 | + smallBody: (_) => ListView.builder( |
| 25 | + itemCount: children.length, |
| 26 | + itemBuilder: (_, idx) => children[idx] |
| 27 | + ), |
| 28 | + body: (_) => GridView.count(crossAxisCount: 2, children: children), |
| 29 | + ) |
| 30 | +``` |
| 31 | +## The Background Widget Suite |
| 32 | +These are the set of widgets that are used on a lower level and offer more customizability at a cost of more lines of code. |
| 33 | +#### AdaptiveLayout: |
| 34 | + |
| 35 | +AdaptiveLayout is the top-level widget class that arranges the layout of the slots and their animation, similar to Scaffold. It takes in several LayoutSlots and returns an appropriate layout based on the diagram above. AdaptiveScaffold is built upon AdaptiveLayout internally but abstracts some of the complexity with presets based on the Material 3 Design specification. |
| 36 | +#### SlotLayout: |
| 37 | +SlotLayout handles the adaptivity or the changes between widgets at certain Breakpoints. It also holds the logic for animating between breakpoints. It takes SlotLayoutConfigs mapped to Breakpoints in a config and displays a widget based on that information. |
| 38 | +#### SlotLayout.from: |
| 39 | +SlotLayout.from creates a SlotLayoutConfig holds the actual widget to be displayed and the entrance animation and exit animation. |
| 40 | +### Example Usage: |
| 41 | + |
| 42 | +<?code-excerpt ...> |
| 43 | +```dart |
| 44 | +AdaptiveLayout( |
| 45 | + primaryNavigation: SlotLayout( |
| 46 | + config: { |
| 47 | + Breakpoints.small: SlotLayout.from(key: const Key('pnav'), builder: (_) => const SizedBox.shrink()), |
| 48 | + Breakpoints.medium: SlotLayout.from( |
| 49 | + inAnimation: leftOutIn, |
| 50 | + key: const Key('pnav1'), |
| 51 | + builder: (_) => AdaptiveScaffold.toNavigationRail(destinations: destinations), |
| 52 | + ), |
| 53 | + Breakpoints.large: SlotLayout.from( |
| 54 | + key: const Key('pnav2'), |
| 55 | + inAnimation: leftOutIn, |
| 56 | + builder: (_) => AdaptiveScaffold.toNavigationRail(extended: true, destinations: destinations), |
| 57 | + ), |
| 58 | + }, |
| 59 | + ), |
| 60 | + body: SlotLayout( |
| 61 | + config: { |
| 62 | + Breakpoints.small: SlotLayout.from( |
| 63 | + key: const Key('body'), |
| 64 | + builder: (_) => ListView.builder( |
| 65 | + itemCount: children.length, |
| 66 | + itemBuilder: (_, idx) => children[idx] |
| 67 | + ), |
| 68 | + ), |
| 69 | + Breakpoints.medium: SlotLayout.from( |
| 70 | + key: const Key('body1'), |
| 71 | + builder: (_) => GridView.count( |
| 72 | + crossAxisCount: 2, |
| 73 | + children: children |
| 74 | + ), |
| 75 | + ), |
| 76 | + }, |
| 77 | + ), |
| 78 | + bottomNavigation: SlotLayout( |
| 79 | + config: { |
| 80 | + Breakpoints.small: SlotLayout.from( |
| 81 | + key: const Key('botnav'), |
| 82 | + inAnimation: bottomToTop, |
| 83 | + builder: (_) => AdaptiveScaffold.toBottomNavigationBar(destinations: destinations), |
| 84 | + ), |
| 85 | + }, |
| 86 | + ), |
| 87 | +) |
| 88 | +``` |
| 89 | +## |
| 90 | +Both of the examples shown here produce the same output: |
| 91 | + |
| 92 | + |
| 93 | +## Additional information |
| 94 | +You can find more information on this package and its usage in the public [design doc](https://docs.google.com/document/d/1qhrpTWYs5f67X8v32NCCNTRMIjSrVHuaMEFAul-Q_Ms/edit?usp=sharing) |
0 commit comments