Skip to content

Commit

Permalink
[adaptive_scaffold] New and Improved Helper Widgets & Updated Example…
Browse files Browse the repository at this point in the history
…s and Their Tests (flutter#2455)

Co-authored-by: Serena Behera <[email protected]>
  • Loading branch information
gspencergoog and rena987 authored Aug 24, 2022
1 parent 15c1fe7 commit f25a05a
Show file tree
Hide file tree
Showing 19 changed files with 1,103 additions and 391 deletions.
4 changes: 4 additions & 0 deletions packages/adaptive_scaffold/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.0.2

* Adds some more examples.

## 0.0.1+1

* Updates text theme parameters to avoid deprecation issues.
Expand Down
187 changes: 127 additions & 60 deletions packages/adaptive_scaffold/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<?code-excerpt path-base="excerpts/packages/adaptive_scaffold_example"?>

# Helper Widgets for Making Adaptive Layouts in Flutter (AdaptiveScaffold)

This package contains some helper widgets that make the process of developing adaptive layouts easier, especially with navigational elements.
Expand All @@ -12,22 +14,55 @@ flutter run --release
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.
### Example Usage:

<?code-excerpt ...>
<?code-excerpt "adaptive_scaffold_demo.dart (Example)"?>
```dart
AdaptiveScaffold(
destinations: const [
NavigationDestination(icon: Icon(Icons.inbox), label: 'Inbox'),
NavigationDestination(icon: Icon(Icons.article), label: 'Articles'),
NavigationDestination(icon: Icon(Icons.chat), label: 'Chat'),
NavigationDestination(icon: Icon(Icons.video_call), label: 'Video'),
],
smallBody: (_) => ListView.builder(
itemCount: children.length,
itemBuilder: (_, idx) => children[idx]
),
body: (_) => GridView.count(crossAxisCount: 2, children: children),
)
@override
Widget build(BuildContext context) {
// Define the children to display within the body at different breakpoints.
final List<Widget> children = <Widget>[
for (int i = 0; i < 10; i++)
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
color: const Color.fromARGB(255, 255, 201, 197), height: 400))
];
return BottomNavigationBarTheme(
data: const BottomNavigationBarThemeData(
unselectedItemColor: Colors.black,
selectedItemColor: Colors.black,
backgroundColor: Colors.white),
child: AdaptiveScaffold(
// An option to override the default breakpoints used for small, medium,
// and large.
smallBreakpoint: const WidthPlatformBreakpoint(end: 700),
mediumBreakpoint:
const WidthPlatformBreakpoint(begin: 700, end: 1000),
largeBreakpoint: const WidthPlatformBreakpoint(begin: 1000),
useDrawer: false,
destinations: const <NavigationDestination>[
NavigationDestination(icon: Icon(Icons.inbox), label: 'Inbox'),
NavigationDestination(
icon: Icon(Icons.article), label: 'Articles'),
NavigationDestination(icon: Icon(Icons.chat), label: 'Chat'),
NavigationDestination(
icon: Icon(Icons.video_call), label: 'Video')
],
body: (_) => GridView.count(crossAxisCount: 2, children: children),
smallBody: (_) => ListView.builder(
itemCount: children.length,
itemBuilder: (_, int idx) => children[idx]),
// Define a default secondaryBody.
secondaryBody: (_) =>
Container(color: const Color.fromARGB(255, 234, 158, 192)),
// Override the default secondaryBody during the smallBreakpoint to be
// empty. Must use AdaptiveScaffold.emptyBuilder to ensure it is properly
// overriden.
smallSecondaryBody: AdaptiveScaffold.emptyBuilder));
}
}
```

## The Background Widget Suite
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.
#### AdaptiveLayout:
Expand All @@ -39,56 +74,88 @@ SlotLayout handles the adaptivity or the changes between widgets at certain Brea
SlotLayout.from creates a SlotLayoutConfig holds the actual widget to be displayed and the entrance animation and exit animation.
### Example Usage:

<?code-excerpt ...>
<?code-excerpt "adaptive_layout_demo.dart (Example)"?>
```dart
AdaptiveLayout(
primaryNavigation: SlotLayout(
config: {
Breakpoints.small: SlotLayout.from(key: const Key('pnav'), builder: (_) => const SizedBox.shrink()),
Breakpoints.medium: SlotLayout.from(
inAnimation: leftOutIn,
key: const Key('pnav1'),
builder: (_) => AdaptiveScaffold.toNavigationRail(destinations: destinations),
),
Breakpoints.large: SlotLayout.from(
key: const Key('pnav2'),
inAnimation: leftOutIn,
builder: (_) => AdaptiveScaffold.toNavigationRail(extended: true, destinations: destinations),
),
},
),
body: SlotLayout(
config: {
Breakpoints.small: SlotLayout.from(
key: const Key('body'),
builder: (_) => ListView.builder(
itemCount: children.length,
itemBuilder: (_, idx) => children[idx]
),
),
Breakpoints.medium: SlotLayout.from(
key: const Key('body1'),
builder: (_) => GridView.count(
crossAxisCount: 2,
children: children
),
),
},
),
bottomNavigation: SlotLayout(
config: {
Breakpoints.small: SlotLayout.from(
key: const Key('botnav'),
inAnimation: bottomToTop,
builder: (_) => AdaptiveScaffold.toBottomNavigationBar(destinations: destinations),
),
},
),
)
// AdaptiveLayout has a number of slots that take SlotLayouts and these
// SlotLayouts' configs take maps of Breakpoints to SlotLayoutConfigs.
return AdaptiveLayout(
// Primary navigation config has nothing from 0 to 600 dp screen width,
// then an unextended NavigationRail with no labels and just icons then an
// extended NavigationRail with both icons and labels.
primaryNavigation: SlotLayout(
config: <Breakpoint, SlotLayoutConfig>{
Breakpoints.medium: SlotLayout.from(
inAnimation: AdaptiveScaffold.leftOutIn,
key: const Key('pnav1'),
builder: (_) => AdaptiveScaffold.standardNavigationRail(
leading: const Icon(Icons.menu),
destinations: destinations
.map((_) => AdaptiveScaffold.toRailDestination(_))
.toList()),
),
Breakpoints.large: SlotLayout.from(
key: const Key('pn1'),
inAnimation: AdaptiveScaffold.leftOutIn,
builder: (_) => AdaptiveScaffold.standardNavigationRail(
extended: true,
leading: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: const <Widget>[
Text('REPLY',
style:
TextStyle(color: Color.fromARGB(255, 255, 201, 197))),
Icon(Icons.menu_open)
],
),
destinations: destinations
.map((_) => AdaptiveScaffold.toRailDestination(_))
.toList(),
trailing: trailingNavRail,
),
),
},
),
// Body switches between a ListView and a GridView from small to medium
// breakpoints and onwards.
body: SlotLayout(
config: <Breakpoint, SlotLayoutConfig>{
Breakpoints.small: SlotLayout.from(
key: const Key('body'),
builder: (_) => ListView.builder(
itemCount: children.length,
itemBuilder: (BuildContext context, int index) => children[index],
),
),
Breakpoints.mediumAndUp: SlotLayout.from(
key: const Key('body1'),
builder: (_) =>
GridView.count(crossAxisCount: 2, children: children),
)
},
),
// BottomNavigation is only active in small views defined as under 600 dp
// width.
bottomNavigation: SlotLayout(
config: <Breakpoint, SlotLayoutConfig>{
Breakpoints.small: SlotLayout.from(
key: const Key('bn'),
inAnimation: AdaptiveScaffold.bottomToTop,
outAnimation: AdaptiveScaffold.topToBottom,
builder: (_) => BottomNavigationBarTheme(
data: const BottomNavigationBarThemeData(
selectedItemColor: Colors.black),
child: AdaptiveScaffold.standardBottomNavigationBar(
destinations: destinations)),
)
},
),
);
}
}
```
##
Both of the examples shown here produce the same output:
!["Example of a display made with AdaptiveScaffold"](example/demo_files/adaptiveScaffold.gif)

## Additional information
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)
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).
16 changes: 16 additions & 0 deletions packages/adaptive_scaffold/example/build.excerpt.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
targets:
$default:
sources:
include:
- lib/**
# Some default includes that aren't really used here but will prevent
# false-negative warnings:
- $package$
- lib/$lib$
exclude:
- '**/.*/**'
- '**/build/**'
builders:
code_excerpter|code_excerpter:
enabled: true

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit f25a05a

Please sign in to comment.