adding packages

This commit is contained in:
2026-01-15 14:38:46 -08:00
parent ef86e3ab6a
commit 6869cf47e5
5253 changed files with 726695 additions and 34 deletions
@@ -0,0 +1,112 @@
# Screenshots
![image](https://github.com/fluttercommunity/responsive_scaffold/blob/master/screenshots/multi-column/1.png)
![image](https://github.com/fluttercommunity/responsive_scaffold/blob/master/screenshots/multi-column/2.png)
![image](https://github.com/fluttercommunity/responsive_scaffold/blob/master/screenshots/multi-column/3.png)
![image](https://github.com/fluttercommunity/responsive_scaffold/blob/master/screenshots/multi-column/4.png)
![image](https://github.com/fluttercommunity/responsive_scaffold/blob/master/screenshots/multi-column/5.png)
![image](https://github.com/fluttercommunity/plugins/blob/master/packages/responsive_scaffold/screenshots/multi-column/5.png)
![image](https://github.com/fluttercommunity/responsive_scaffold/blob/master/screenshots/multi-column/6.png)
![image](https://github.com/fluttercommunity/responsive_scaffold/blob/master/screenshots/multi-column/7.png)
# Example
``` dart
import 'package:flutter/material.dart';
import 'package:responsive_scaffold/responsive_scaffold.dart';
class MultiColumnNavigationExample extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ThreeColumnNavigation(
title: Text('Mailboxes'),
showDetailsArrows: true,
backgroundColor: Colors.grey[100],
bottomAppBar: BottomAppBar(
elevation: 1,
child: Row(
children: <Widget>[
IconButton(
icon: Icon(
Icons.filter_list,
color: Colors.transparent,
),
onPressed: () {},
),
],
),
),
sections: [
MainSection(
label: Text('All Inboxes'),
icon: Icon(Icons.mail),
itemCount: 100,
itemBuilder: (context, index, selected) {
return ListTile(
leading: CircleAvatar(
child: Text(index.toString()),
),
selected: selected,
title: Text('Primary Information'),
subtitle: Text('Here are some details about the item'),
);
},
bottomAppBar: BottomAppBar(
elevation: 1,
child: Row(
children: <Widget>[
IconButton(
icon: Icon(Icons.filter_list),
onPressed: () {},
),
],
),
),
getDetails: (context, index) {
return DetailsWidget(
title: Text('Details'),
child: Center(
child: Text(
index.toString(),
),
),
);
},
),
MainSection(
label: Text('Sent Mail'),
icon: Icon(Icons.send),
itemCount: 100,
itemBuilder: (context, index, selected) {
return ListTile(
leading: CircleAvatar(
child: Text(index.toString()),
),
selected: selected,
title: Text('Secondary Information'),
subtitle: Text('Here are some details about the item'),
);
},
getDetails: (context, index) {
return DetailsWidget(
title: Text('Details'),
actions: [
IconButton(
icon: Icon(Icons.share),
onPressed: () {},
),
],
child: Center(
child: Text(
index.toString(),
),
),
);
},
),
],
);
}
}
```
@@ -0,0 +1,66 @@
import 'package:flutter/material.dart';
import '../three_column_navigation.dart';
class DetailsView extends StatelessWidget {
const DetailsView({
Key key,
@required int listIndex,
@required DetailsWidget details,
this.previous,
this.next,
this.isLast = false,
this.isFirst = false,
this.automaticallyImplyLeading = true,
this.showDetailsArrows = false,
this.scaffoldKey,
}) : _listIndex = listIndex,
_details = details,
super(key: key);
final int _listIndex;
final DetailsWidget _details;
final VoidCallback previous, next;
final bool showDetailsArrows;
final bool isLast, isFirst;
final bool automaticallyImplyLeading;
final GlobalKey<ScaffoldState> scaffoldKey;
@override
Widget build(BuildContext context) {
return Scaffold(
key: scaffoldKey,
appBar: AppBar(
automaticallyImplyLeading: automaticallyImplyLeading,
title: !showDetailsArrows
? _details.title
: Row(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
IconButton(
icon: Icon(Icons.arrow_upward),
onPressed: isFirst ? null : previous,
),
IconButton(
icon: Icon(Icons.arrow_downward),
onPressed: isLast ? null : next,
),
],
),
if (_details?.title != null)
Expanded(
child: Center(child: _details.title),
),
],
),
actions: _details?.actions,
),
body: _details.child,
bottomNavigationBar: _details?.bottomAppBar,
);
}
}
@@ -0,0 +1,3 @@
export 'details.dart';
export 'section_list.dart';
export 'sections.dart';
@@ -0,0 +1,41 @@
import 'package:flutter/material.dart';
import 'package:scroll_to_index/scroll_to_index.dart';
import '../three_column_navigation.dart';
class SectionList extends StatelessWidget {
const SectionList({
Key key,
@required this.controller,
@required MainSection section,
@required int listIndex,
@required this.listTap,
}) : _section = section,
_listIndex = listIndex,
super(key: key);
final AutoScrollController controller;
final MainSection _section;
final int _listIndex;
final ValueChanged<int> listTap;
@override
Widget build(BuildContext context) {
return ListView.builder(
controller: controller,
itemBuilder: (context, index) {
final _item = _section.itemBuilder(context, index, _listIndex == index);
return AutoScrollTag(
controller: controller,
key: ValueKey(index),
index: index,
child: GestureDetector(
child: _item,
onTap: () => listTap(index),
),
);
},
itemCount: _section.itemCount,
);
}
}
@@ -0,0 +1,33 @@
import 'package:flutter/material.dart';
import '../three_column_navigation.dart';
class SectionsList extends StatelessWidget {
const SectionsList({
Key key,
@required this.sectionTap,
@required int sectionIndex,
@required this.sections,
}) : _sectionIndex = sectionIndex,
super(key: key);
final int _sectionIndex;
final ValueChanged<int> sectionTap;
final List<MainSection> sections;
@override
Widget build(BuildContext context) {
return ListView.builder(
itemBuilder: (context, index) {
final _item = sections[index];
return ListTile(
leading: _item.icon,
title: _item.label,
selected: index == _sectionIndex,
onTap: () => sectionTap(index),
);
},
itemCount: sections.length,
);
}
}
@@ -0,0 +1,341 @@
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:scroll_to_index/scroll_to_index.dart';
import 'common/index.dart';
class ThreeColumnNavigation extends StatefulWidget {
ThreeColumnNavigation({
@required this.sections,
this.showDetailsArrows = true,
this.expandedIconData = Icons.fullscreen_exit,
this.collapsedIconData = Icons.fullscreen,
this.initiallyExpanded = true,
this.bottomAppBar,
this.backgroundColor,
this.title,
});
final Color backgroundColor;
final Widget bottomAppBar;
final IconData expandedIconData, collapsedIconData;
final bool initiallyExpanded;
List<MainSection> sections;
final bool showDetailsArrows;
final Text title;
@override
_ThreeColumnNavigationState createState() => _ThreeColumnNavigationState();
}
class _ThreeColumnNavigationState extends State<ThreeColumnNavigation> {
AutoScrollController controller;
bool _expanded = true;
int _listIndex = 0;
final _scaffoldKey = GlobalKey<ScaffoldState>();
int _sectionIndex = 0;
@override
void initState() {
if (!widget.initiallyExpanded) if (mounted)
setState(() {
_expanded = false;
});
_setUpController(true);
super.initState();
}
void _setUpController(bool init) {
controller = AutoScrollController(
viewportBoundaryGetter: () =>
Rect.fromLTRB(0, 0, 0, MediaQuery.of(context).padding.bottom),
axis: Axis.vertical,
);
}
Future _scrollToIndex(int value,
{AutoScrollPosition position = AutoScrollPosition.middle}) async {
try {
controller.scrollToIndex(
value,
preferPosition: position,
);
// controller.highlight(value);
} on Exception catch (e) {
print('Could not scroll to index: $value => $e');
}
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth > 720) {
final _showMenu = constraints.maxWidth < 1100;
if (_showMenu) {
_expanded = false;
}
return Material(
child: Row(
children: <Widget>[
if (_expanded)
Container(
width: 300,
child: Scaffold(
backgroundColor: widget?.backgroundColor,
appBar: AppBar(
title: widget?.title,
leading: IconButton(
icon: Icon(widget.expandedIconData),
onPressed: () {
if (mounted)
setState(() {
_expanded = false;
});
},
),
),
body: SectionsList(
sections: widget.sections,
sectionIndex: _sectionIndex,
sectionTap: (index) {
if (_sectionIndex != index) {
if (mounted)
setState(() {
_sectionIndex = index;
});
_setUpController(false);
}
},
),
bottomNavigationBar: widget?.bottomAppBar,
),
),
Container(
width: 400,
child: Scaffold(
drawerScrimColor: Colors.transparent,
drawer: _showMenu
? SectionsDrawer(
sections: widget.sections,
sectionIndex: _sectionIndex,
sectionChanged: (context, index) {
if (_sectionIndex != index) {
if (mounted)
setState(() {
_sectionIndex = index;
});
_setUpController(false);
Navigator.pop(context);
}
},
)
: null,
appBar: AppBar(
leading: _showMenu
? MenuButton(scaffoldKey: _scaffoldKey)
: !_expanded
? IconButton(
icon: Icon(widget.collapsedIconData),
onPressed: () {
if (mounted)
setState(() {
_expanded = true;
});
},
)
: null,
title: widget.sections[_sectionIndex].label,
),
body: SectionList(
controller: controller,
section: widget.sections[_sectionIndex],
listIndex: _listIndex,
listTap: (index) {
if (_listIndex != index) {
if (mounted)
setState(() {
_listIndex = index;
});
}
},
),
bottomNavigationBar:
widget.sections[_sectionIndex]?.bottomAppBar,
),
),
Expanded(
child: Container(
child: Stack(
children: <Widget>[
DetailsView(
scaffoldKey: _scaffoldKey,
automaticallyImplyLeading: false,
isFirst: _listIndex == 0,
isLast: widget.sections[_sectionIndex].itemCount ==
_listIndex + 1,
listIndex: _listIndex,
details: widget.sections[_sectionIndex]
.getDetails(context, _listIndex),
showDetailsArrows: widget.showDetailsArrows,
previous: () {
if (mounted)
setState(() {
_listIndex--;
});
_scrollToIndex(_listIndex);
},
next: () {
if (mounted)
setState(() {
_listIndex++;
});
_scrollToIndex(_listIndex);
},
),
],
),
),
),
],
),
);
}
return Scaffold(
drawer: SectionsDrawer(
sections: widget.sections,
sectionIndex: _sectionIndex,
sectionChanged: (context, index) {
if (_sectionIndex != index) {
if (mounted)
setState(() {
_sectionIndex = index;
});
_setUpController(false);
Navigator.pop(context);
}
},
),
appBar: AppBar(
title: widget.sections[_sectionIndex]?.label,
),
body: SectionList(
controller: controller,
section: widget.sections[_sectionIndex],
listIndex: _listIndex,
listTap: (index) {
if (_listIndex != index) {
if (mounted)
setState(() {
_listIndex = index;
});
Navigator.of(context).push(MaterialPageRoute(
builder: (_) {
final _details = widget.sections[_sectionIndex]
.getDetails(context, _listIndex);
return DetailsView(
isFirst: _listIndex == 0,
isLast: widget.sections.isNotEmpty &&
_listIndex == widget.sections.length - 1,
listIndex: _listIndex,
details: _details,
showDetailsArrows: false,
);
},
));
}
},
),
bottomNavigationBar: widget.sections[_sectionIndex]?.bottomAppBar,
);
},
);
}
}
class MenuButton extends StatelessWidget {
const MenuButton({
Key key,
@required GlobalKey<ScaffoldState> scaffoldKey,
}) : _scaffoldKey = scaffoldKey,
super(key: key);
final GlobalKey<ScaffoldState> _scaffoldKey;
@override
Widget build(BuildContext context) {
return IconButton(
icon: Icon(Icons.menu),
onPressed: () {
Scaffold.of(context).openDrawer();
// _scaffoldKey.currentState.showBodyScrim(true, 0.5);
},
);
}
}
class SectionsDrawer extends StatelessWidget {
const SectionsDrawer({
Key key,
@required int sectionIndex,
@required this.sectionChanged,
@required this.sections,
}) : _sectionIndex = sectionIndex,
super(key: key);
final List<MainSection> sections;
final int _sectionIndex;
final Function(BuildContext, int) sectionChanged;
@override
Widget build(BuildContext context) {
return Drawer(
child: SectionsList(
sections: sections,
sectionIndex: _sectionIndex,
sectionTap: (index) => sectionChanged(context, index),
),
);
}
}
class MainSection {
const MainSection({
@required this.itemBuilder,
@required this.itemCount,
@required this.getDetails,
@required this.icon,
@required this.label,
this.bottomAppBar,
});
final Widget bottomAppBar;
final Icon icon;
final int itemCount;
final Text label;
final Widget Function(BuildContext context, int index, bool selected)
itemBuilder;
final DetailsWidget Function(BuildContext context, int index) getDetails;
}
class DetailsWidget {
const DetailsWidget({
@required this.child,
this.actions,
this.title,
this.bottomAppBar,
});
final List<Widget> actions;
final Widget bottomAppBar;
final Widget child;
final Text title;
}