Skip to content

Instantly share code, notes, and snippets.

@maks
Forked from rodydavis/adaptive_scaffold.dart
Last active November 8, 2022 06:16
Show Gist options
  • Save maks/38d0b82c398ed84386f101b481f7e653 to your computer and use it in GitHub Desktop.
Save maks/38d0b82c398ed84386f101b481f7e653 to your computer and use it in GitHub Desktop.
Flutter Adaptive Scaffold
import 'package:flutter/material.dart';
// Updated to Flutter 3 by @maks
// original from: https://gist.github.com/rodydavis/5c7b3365ba9c4b010cace84ca20c2bcc
const kTabletBreakpoint = 720.0;
const kDesktopBreakpoint = 1200.0;
const kSideMenuWidth = 250.0;
class AdaptiveScaffold extends StatelessWidget {
final List<TabItem> tabs;
final int selectedIndex;
final ValueChanged<int> onSelectionChanged;
const AdaptiveScaffold({
Key? key,
required this.tabs,
required this.selectedIndex,
required this.onSelectionChanged,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (_, dimens) {
if (dimens.maxWidth >= kDesktopBreakpoint) {
return Scaffold(
body: Row(
children: [
SizedBox(
width: kSideMenuWidth,
child: ListView(
children: [
for (var i = 0; i < tabs.length; i++)
ListTile(
selected: selectedIndex == i,
title: Text(tabs[i].label),
leading: tabs[i].icon,
onTap: () => onSelectionChanged(i),
),
],
),
),
Expanded(
child: buildBody(selectedIndex, tabs),
),
],
),
);
} else if (dimens.maxWidth >= kTabletBreakpoint) {
return Scaffold(
body: Row(
children: [
NavigationRail(
selectedIconTheme: IconThemeData(
color: Theme.of(context).colorScheme.secondary,
),
selectedLabelTextStyle: TextStyle(
color: Theme.of(context).colorScheme.secondary,
),
labelType: NavigationRailLabelType.all,
selectedIndex: selectedIndex,
onDestinationSelected: (val) => onSelectionChanged(val),
destinations: [
for (final item in tabs)
NavigationRailDestination(
label: Text(item.label),
icon: item.icon,
),
],
),
Expanded(
child: buildBody(selectedIndex, tabs),
),
],
),
);
} else {
return Scaffold(
body: buildBody(selectedIndex, tabs),
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
currentIndex: selectedIndex,
onTap: (val) => onSelectionChanged(val),
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
items: [
for (final item in tabs)
BottomNavigationBarItem(
label: item.label,
icon: item.icon,
),
],
),
);
}
},
);
}
Widget buildBody(int selectedIndex, List<TabItem> tabs) {
return IndexedStack(
index: selectedIndex,
children: [
for (final item in tabs) item.body,
],
);
}
}
class TabItem {
final Widget body;
final String label;
final Icon icon;
const TabItem({
required this.body,
required this.label,
required this.icon,
});
}
@maks
Copy link
Author

maks commented Nov 8, 2022

updated from original for modern Dart, Flutter 3.3, uses Scaffold instead of just Material widgets

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment