adding packages
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class DetailsScreen {
|
||||
const DetailsScreen({
|
||||
this.appBar,
|
||||
@required this.body,
|
||||
});
|
||||
|
||||
final Widget body;
|
||||
final PreferredSizeWidget appBar;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
export 'package:responsive_scaffold/data/classes/details.dart';
|
||||
export 'package:responsive_scaffold/templates/list/responsive_list.dart';
|
||||
export 'package:responsive_scaffold/templates/layout/scaffold.dart';
|
||||
export 'package:responsive_scaffold/templates/3-column/three_column_navigation.dart';
|
||||
@@ -0,0 +1,112 @@
|
||||
# Screenshots
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
# 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;
|
||||
}
|
||||
@@ -0,0 +1,236 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ResponsiveScaffold extends StatelessWidget {
|
||||
const ResponsiveScaffold({
|
||||
this.scaffoldKey,
|
||||
this.drawer,
|
||||
this.endDrawer,
|
||||
this.title,
|
||||
this.body,
|
||||
this.trailing,
|
||||
this.floatingActionButton,
|
||||
this.menuIcon,
|
||||
this.endIcon,
|
||||
this.kTabletBreakpoint = 720.0,
|
||||
this.kDesktopBreakpoint = 1440.0,
|
||||
this.appBarElevation,
|
||||
});
|
||||
|
||||
final Widget drawer, endDrawer;
|
||||
|
||||
final Widget title;
|
||||
|
||||
final Widget body;
|
||||
|
||||
final Widget trailing;
|
||||
|
||||
final Widget floatingActionButton;
|
||||
|
||||
final kTabletBreakpoint;
|
||||
final kDesktopBreakpoint;
|
||||
final _drawerWidth = 304.0;
|
||||
|
||||
final IconData menuIcon, endIcon;
|
||||
|
||||
final double appBarElevation;
|
||||
|
||||
final Key scaffoldKey;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LayoutBuilder(
|
||||
builder: (_, constraints) {
|
||||
if (constraints.maxWidth >= kDesktopBreakpoint) {
|
||||
return Material(
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
if (drawer != null) ...[
|
||||
SizedBox(
|
||||
width: _drawerWidth,
|
||||
child: Drawer(
|
||||
child: SafeArea(
|
||||
child: drawer,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
Expanded(
|
||||
child: Scaffold(
|
||||
key: scaffoldKey,
|
||||
appBar: AppBar(
|
||||
elevation: appBarElevation,
|
||||
automaticallyImplyLeading: false,
|
||||
title: title,
|
||||
actions: <Widget>[
|
||||
if (trailing != null) ...[
|
||||
trailing,
|
||||
],
|
||||
],
|
||||
),
|
||||
body: Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: body ?? Container(),
|
||||
),
|
||||
if (endDrawer != null) ...[
|
||||
Container(
|
||||
width: _drawerWidth,
|
||||
child: Drawer(
|
||||
elevation: 3.0,
|
||||
child: SafeArea(
|
||||
child: endDrawer,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (floatingActionButton != null) ...[
|
||||
Positioned(
|
||||
top: 100.0,
|
||||
left: _drawerWidth - 30,
|
||||
child: floatingActionButton,
|
||||
)
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
if (constraints.maxWidth >= kTabletBreakpoint) {
|
||||
return Scaffold(
|
||||
key: scaffoldKey,
|
||||
drawer: drawer == null
|
||||
? null
|
||||
: Drawer(
|
||||
child: SafeArea(
|
||||
child: drawer,
|
||||
),
|
||||
),
|
||||
appBar: AppBar(
|
||||
elevation: appBarElevation,
|
||||
automaticallyImplyLeading: false,
|
||||
title: title,
|
||||
leading: _MenuButton(iconData: menuIcon),
|
||||
actions: <Widget>[
|
||||
if (trailing != null) ...[
|
||||
trailing,
|
||||
],
|
||||
],
|
||||
),
|
||||
body: SafeArea(
|
||||
right: false,
|
||||
bottom: false,
|
||||
child: Stack(
|
||||
children: <Widget>[
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: body ?? Container(),
|
||||
),
|
||||
if (endDrawer != null) ...[
|
||||
Container(
|
||||
width: _drawerWidth,
|
||||
child: Drawer(
|
||||
elevation: 3.0,
|
||||
child: SafeArea(
|
||||
child: endDrawer,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
if (floatingActionButton != null) ...[
|
||||
Positioned(
|
||||
top: 10.0,
|
||||
left: 10.0,
|
||||
child: floatingActionButton,
|
||||
)
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return Scaffold(
|
||||
key: scaffoldKey,
|
||||
drawer: drawer == null
|
||||
? null
|
||||
: Drawer(
|
||||
child: SafeArea(
|
||||
child: drawer,
|
||||
),
|
||||
),
|
||||
endDrawer: endDrawer == null
|
||||
? null
|
||||
: Drawer(
|
||||
child: SafeArea(
|
||||
child: endDrawer,
|
||||
),
|
||||
),
|
||||
appBar: AppBar(
|
||||
elevation: appBarElevation,
|
||||
automaticallyImplyLeading: false,
|
||||
leading: _MenuButton(iconData: menuIcon),
|
||||
title: title,
|
||||
actions: <Widget>[
|
||||
if (trailing != null) ...[
|
||||
trailing,
|
||||
],
|
||||
if (endDrawer != null) ...[
|
||||
_OptionsButton(iconData: endIcon),
|
||||
]
|
||||
],
|
||||
),
|
||||
body: body,
|
||||
floatingActionButton: floatingActionButton,
|
||||
floatingActionButtonLocation: FloatingActionButtonLocation.endFloat,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _OptionsButton extends StatelessWidget {
|
||||
const _OptionsButton({
|
||||
Key key,
|
||||
@required this.iconData,
|
||||
}) : super(key: key);
|
||||
|
||||
final IconData iconData;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return IconButton(
|
||||
icon: Icon(iconData ?? Icons.more_vert),
|
||||
onPressed: () {
|
||||
Scaffold.of(context).openEndDrawer();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _MenuButton extends StatelessWidget {
|
||||
const _MenuButton({
|
||||
Key key,
|
||||
@required this.iconData,
|
||||
}) : super(key: key);
|
||||
|
||||
final IconData iconData;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return IconButton(
|
||||
icon: Icon(iconData ?? Icons.menu),
|
||||
onPressed: () {
|
||||
Scaffold.of(context).openDrawer();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,241 @@
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'responsive_list.dart';
|
||||
import 'views/index.dart';
|
||||
|
||||
export 'package:responsive_scaffold/data/classes/details.dart';
|
||||
|
||||
class ResponsiveListScaffold extends StatelessWidget {
|
||||
ResponsiveListScaffold({
|
||||
this.tabletBreakpoint = 720.0,
|
||||
@required this.detailBuilder,
|
||||
this.appBar,
|
||||
this.drawer,
|
||||
this.slivers,
|
||||
this.endDrawer,
|
||||
@required List<Widget> children,
|
||||
this.primary = true,
|
||||
// this.extendBody = false,
|
||||
this.drawerDragStartBehavior = DragStartBehavior.start,
|
||||
this.backgroundColor,
|
||||
this.bottomNavigationBar,
|
||||
this.bottomSheet,
|
||||
this.floatingActionButton,
|
||||
this.floatingActionButtonAnimator,
|
||||
this.floatingActionButtonLocation,
|
||||
this.persistentFooterButtons,
|
||||
this.resizeToAvoidBottomInset,
|
||||
this.resizeToAvoidBottomPadding,
|
||||
this.tabletItemNotSelected,
|
||||
this.tabletSideMenu,
|
||||
this.nullItems,
|
||||
this.emptyItems,
|
||||
this.tabletFlexDetailView = 8,
|
||||
this.tabletFlexListView = 3,
|
||||
this.scaffoldKey,
|
||||
this.detailScaffoldKey,
|
||||
this.mobileRootNavigator = false,
|
||||
this.mobileNavigator,
|
||||
}) : childDelagate = SliverChildListDelegate(
|
||||
children,
|
||||
addAutomaticKeepAlives: false,
|
||||
addRepaintBoundaries: false,
|
||||
addSemanticIndexes: false,
|
||||
);
|
||||
|
||||
ResponsiveListScaffold.builder({
|
||||
this.tabletBreakpoint = 720.0,
|
||||
@required this.detailBuilder,
|
||||
this.appBar,
|
||||
this.drawer,
|
||||
this.slivers,
|
||||
this.endDrawer,
|
||||
@required int itemCount,
|
||||
@required IndexedWidgetBuilder itemBuilder,
|
||||
this.primary = true,
|
||||
// this.extendBody = false,
|
||||
this.drawerDragStartBehavior = DragStartBehavior.start,
|
||||
this.backgroundColor,
|
||||
this.bottomNavigationBar,
|
||||
this.bottomSheet,
|
||||
this.floatingActionButton,
|
||||
this.nullItems,
|
||||
this.emptyItems,
|
||||
this.floatingActionButtonAnimator,
|
||||
this.floatingActionButtonLocation,
|
||||
this.persistentFooterButtons,
|
||||
this.resizeToAvoidBottomInset,
|
||||
this.resizeToAvoidBottomPadding,
|
||||
this.tabletItemNotSelected,
|
||||
this.tabletSideMenu,
|
||||
this.tabletFlexDetailView = 8,
|
||||
this.tabletFlexListView = 4,
|
||||
this.scaffoldKey,
|
||||
this.detailScaffoldKey,
|
||||
this.mobileRootNavigator = false,
|
||||
this.mobileNavigator,
|
||||
}) : childDelagate = SliverChildBuilderDelegate(
|
||||
itemBuilder,
|
||||
childCount: itemCount,
|
||||
addAutomaticKeepAlives: false,
|
||||
addRepaintBoundaries: false,
|
||||
addSemanticIndexes: false,
|
||||
);
|
||||
|
||||
ResponsiveListScaffold.custom({
|
||||
this.tabletBreakpoint = 720.0,
|
||||
@required this.detailBuilder,
|
||||
this.appBar,
|
||||
this.drawer,
|
||||
this.slivers,
|
||||
this.endDrawer,
|
||||
@required this.childDelagate,
|
||||
this.primary = true,
|
||||
// this.extendBody = false,
|
||||
this.drawerDragStartBehavior = DragStartBehavior.start,
|
||||
this.backgroundColor,
|
||||
this.bottomNavigationBar,
|
||||
this.bottomSheet,
|
||||
this.floatingActionButton,
|
||||
this.nullItems,
|
||||
this.emptyItems,
|
||||
this.floatingActionButtonAnimator,
|
||||
this.floatingActionButtonLocation,
|
||||
this.persistentFooterButtons,
|
||||
this.resizeToAvoidBottomInset,
|
||||
this.resizeToAvoidBottomPadding,
|
||||
this.tabletItemNotSelected,
|
||||
this.tabletSideMenu,
|
||||
this.tabletFlexDetailView = 8,
|
||||
this.tabletFlexListView = 4,
|
||||
this.scaffoldKey,
|
||||
this.detailScaffoldKey,
|
||||
this.mobileRootNavigator = false,
|
||||
this.mobileNavigator,
|
||||
});
|
||||
|
||||
final double tabletBreakpoint;
|
||||
|
||||
final DetailWidgetBuilder detailBuilder;
|
||||
|
||||
final PreferredSizeWidget appBar;
|
||||
|
||||
final Widget drawer, endDrawer;
|
||||
|
||||
final List<Widget> slivers;
|
||||
|
||||
final Widget floatingActionButton;
|
||||
|
||||
final FloatingActionButtonLocation floatingActionButtonLocation;
|
||||
|
||||
final Widget bottomNavigationBar;
|
||||
|
||||
final Widget bottomSheet;
|
||||
|
||||
final List<Widget> persistentFooterButtons;
|
||||
|
||||
final FloatingActionButtonAnimator floatingActionButtonAnimator;
|
||||
|
||||
final bool resizeToAvoidBottomPadding;
|
||||
|
||||
final bool resizeToAvoidBottomInset;
|
||||
|
||||
final bool primary;
|
||||
|
||||
// final bool extendBody;
|
||||
|
||||
final DragStartBehavior drawerDragStartBehavior;
|
||||
|
||||
final Color backgroundColor;
|
||||
|
||||
final Key scaffoldKey, detailScaffoldKey;
|
||||
|
||||
final Widget tabletItemNotSelected;
|
||||
|
||||
final Flexible tabletSideMenu;
|
||||
|
||||
final int tabletFlexListView;
|
||||
|
||||
final int tabletFlexDetailView;
|
||||
|
||||
final bool mobileRootNavigator;
|
||||
|
||||
final NavigatorState mobileNavigator;
|
||||
|
||||
final Widget nullItems, emptyItems;
|
||||
|
||||
final SliverChildDelegate childDelagate;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return LayoutBuilder(
|
||||
builder: (_, constraints) {
|
||||
if (constraints.maxWidth >= tabletBreakpoint) {
|
||||
// Tablet
|
||||
return TabletView.custom(
|
||||
key: key,
|
||||
nullItems: nullItems,
|
||||
emptyItems: emptyItems,
|
||||
scaffoldkey: scaffoldKey,
|
||||
detailScaffoldKey: detailScaffoldKey,
|
||||
drawerDragStartBehavior: drawerDragStartBehavior,
|
||||
floatingActionButton: floatingActionButton,
|
||||
floatingActionButtonLocation: floatingActionButtonLocation,
|
||||
bottomNavigationBar: bottomNavigationBar,
|
||||
bottomSheet: bottomSheet,
|
||||
persistentFooterButtons: persistentFooterButtons,
|
||||
floatingActionButtonAnimator: floatingActionButtonAnimator,
|
||||
resizeToAvoidBottomInset: resizeToAvoidBottomInset,
|
||||
resizeToAvoidBottomPadding: resizeToAvoidBottomPadding,
|
||||
primary: primary,
|
||||
// extendBody: extendBody,
|
||||
backgroundColor: backgroundColor,
|
||||
drawer: drawer,
|
||||
endDrawer: endDrawer,
|
||||
appBar: appBar,
|
||||
slivers: slivers,
|
||||
detailBuilder: detailBuilder,
|
||||
childDelagate: childDelagate,
|
||||
flexDetailView: tabletFlexDetailView,
|
||||
flexListView: tabletFlexListView,
|
||||
sideMenu: tabletSideMenu,
|
||||
itemNotSelected: tabletItemNotSelected,
|
||||
);
|
||||
}
|
||||
|
||||
// Mobile
|
||||
return Scaffold(
|
||||
key: scaffoldKey,
|
||||
floatingActionButton: floatingActionButton,
|
||||
floatingActionButtonLocation: floatingActionButtonLocation,
|
||||
bottomNavigationBar: bottomNavigationBar,
|
||||
bottomSheet: bottomSheet,
|
||||
persistentFooterButtons: persistentFooterButtons,
|
||||
floatingActionButtonAnimator: floatingActionButtonAnimator,
|
||||
resizeToAvoidBottomInset: resizeToAvoidBottomInset,
|
||||
resizeToAvoidBottomPadding: resizeToAvoidBottomPadding,
|
||||
primary: primary,
|
||||
// extendBody: extendBody,
|
||||
backgroundColor: backgroundColor,
|
||||
drawer: drawer,
|
||||
endDrawer: endDrawer,
|
||||
appBar: appBar,
|
||||
body: MobileView.custom(
|
||||
useRootNavigator: mobileRootNavigator,
|
||||
nullItems: nullItems,
|
||||
emptyItems: emptyItems,
|
||||
slivers: slivers,
|
||||
detailScaffoldKey: detailScaffoldKey,
|
||||
detailBuilder: detailBuilder,
|
||||
childDelagate: childDelagate,
|
||||
navigator: mobileNavigator,
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
typedef DetailWidgetBuilder = DetailsScreen Function(
|
||||
BuildContext context, int index, bool tablet);
|
||||
@@ -0,0 +1,2 @@
|
||||
export 'mobile.dart';
|
||||
export 'tablet.dart';
|
||||
@@ -0,0 +1,136 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../responsive_scaffold.dart';
|
||||
import '../responsive_list.dart';
|
||||
|
||||
class MobileView extends StatelessWidget {
|
||||
MobileView({
|
||||
Key key,
|
||||
@required this.slivers,
|
||||
@required this.detailBuilder,
|
||||
@required List<Widget> children,
|
||||
@required this.detailScaffoldKey,
|
||||
@required this.useRootNavigator,
|
||||
@required this.navigator,
|
||||
@required this.nullItems,
|
||||
@required this.emptyItems,
|
||||
}) : childDelagate = SliverChildListDelegate(
|
||||
children,
|
||||
addAutomaticKeepAlives: false,
|
||||
addRepaintBoundaries: false,
|
||||
addSemanticIndexes: false,
|
||||
),
|
||||
super(key: key);
|
||||
|
||||
MobileView.builder({
|
||||
Key key,
|
||||
@required this.slivers,
|
||||
@required this.detailBuilder,
|
||||
@required int itemCount,
|
||||
@required IndexedWidgetBuilder itemBuilder,
|
||||
@required this.detailScaffoldKey,
|
||||
@required this.useRootNavigator,
|
||||
@required this.navigator,
|
||||
@required this.nullItems,
|
||||
@required this.emptyItems,
|
||||
}) : childDelagate = SliverChildBuilderDelegate(
|
||||
itemBuilder,
|
||||
childCount: itemCount,
|
||||
addAutomaticKeepAlives: false,
|
||||
addRepaintBoundaries: false,
|
||||
addSemanticIndexes: false,
|
||||
),
|
||||
super(key: key);
|
||||
|
||||
MobileView.custom({
|
||||
Key key,
|
||||
@required this.slivers,
|
||||
@required this.detailBuilder,
|
||||
@required this.childDelagate,
|
||||
@required this.detailScaffoldKey,
|
||||
@required this.useRootNavigator,
|
||||
@required this.navigator,
|
||||
@required this.nullItems,
|
||||
@required this.emptyItems,
|
||||
}) : super(key: key);
|
||||
|
||||
final List<Widget> slivers;
|
||||
final DetailWidgetBuilder detailBuilder;
|
||||
final Key detailScaffoldKey;
|
||||
final bool useRootNavigator;
|
||||
final NavigatorState navigator;
|
||||
final Widget nullItems, emptyItems;
|
||||
final SliverChildDelegate childDelagate;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return CustomScrollView(
|
||||
slivers: <Widget>[]
|
||||
..addAll(slivers ?? [])
|
||||
..add(Builder(
|
||||
builder: (BuildContext context) {
|
||||
if (childDelagate?.estimatedChildCount == null && nullItems != null)
|
||||
return SliverFillRemaining(child: nullItems);
|
||||
if (childDelagate?.estimatedChildCount != null &&
|
||||
childDelagate.estimatedChildCount == 0 &&
|
||||
emptyItems != null)
|
||||
return SliverFillRemaining(child: emptyItems);
|
||||
return SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(BuildContext context, int index) {
|
||||
return new KeepAlive(
|
||||
keepAlive: true,
|
||||
child: new IndexedSemantics(
|
||||
index: index,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
(navigator ?? Navigator.of(context))
|
||||
.push(MaterialPageRoute(builder: (context) {
|
||||
final _details = detailBuilder(context, index, false);
|
||||
return new DetailView(
|
||||
detailScaffoldKey: detailScaffoldKey,
|
||||
itemCount: childDelagate.estimatedChildCount,
|
||||
details: _details);
|
||||
}));
|
||||
},
|
||||
child: new Container(
|
||||
padding: const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: childDelagate.build(context, index),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
childCount: childDelagate?.estimatedChildCount ?? 0,
|
||||
addAutomaticKeepAlives: false,
|
||||
addRepaintBoundaries: false,
|
||||
addSemanticIndexes: false,
|
||||
));
|
||||
},
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DetailView extends StatelessWidget {
|
||||
const DetailView({
|
||||
Key key,
|
||||
@required this.itemCount,
|
||||
@required DetailsScreen details,
|
||||
@required this.detailScaffoldKey,
|
||||
}) : _details = details,
|
||||
super(key: key);
|
||||
|
||||
final int itemCount;
|
||||
final DetailsScreen _details;
|
||||
final Key detailScaffoldKey;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
key: detailScaffoldKey,
|
||||
appBar: _details?.appBar,
|
||||
body: _details.body,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import '../../../responsive_scaffold.dart';
|
||||
import '../responsive_list.dart';
|
||||
|
||||
class TabletView extends StatefulWidget {
|
||||
TabletView({
|
||||
Key key,
|
||||
@required this.slivers,
|
||||
@required this.detailBuilder,
|
||||
@required List<Widget> children,
|
||||
@required this.itemNotSelected,
|
||||
@required this.sideMenu,
|
||||
this.flexListView = 4,
|
||||
this.flexDetailView = 8,
|
||||
@required this.appBar,
|
||||
@required this.backgroundColor,
|
||||
@required this.bottomNavigationBar,
|
||||
@required this.bottomSheet,
|
||||
@required this.drawer,
|
||||
@required this.drawerDragStartBehavior,
|
||||
@required this.endDrawer,
|
||||
@required this.floatingActionButton,
|
||||
@required this.floatingActionButtonAnimator,
|
||||
@required this.floatingActionButtonLocation,
|
||||
@required this.persistentFooterButtons,
|
||||
@required this.primary,
|
||||
@required this.resizeToAvoidBottomInset,
|
||||
@required this.resizeToAvoidBottomPadding,
|
||||
@required this.scaffoldkey,
|
||||
@required this.detailScaffoldKey,
|
||||
@required this.nullItems,
|
||||
@required this.emptyItems,
|
||||
}) : childDelagate = SliverChildListDelegate(
|
||||
children,
|
||||
addAutomaticKeepAlives: false,
|
||||
addRepaintBoundaries: false,
|
||||
addSemanticIndexes: false,
|
||||
),
|
||||
super(key: key);
|
||||
|
||||
TabletView.builder({
|
||||
Key key,
|
||||
@required this.slivers,
|
||||
@required this.detailBuilder,
|
||||
@required int itemCount,
|
||||
@required IndexedWidgetBuilder itemBuilder,
|
||||
@required this.itemNotSelected,
|
||||
@required this.sideMenu,
|
||||
this.flexListView = 4,
|
||||
this.flexDetailView = 8,
|
||||
@required this.appBar,
|
||||
@required this.backgroundColor,
|
||||
@required this.bottomNavigationBar,
|
||||
@required this.bottomSheet,
|
||||
@required this.drawer,
|
||||
@required this.drawerDragStartBehavior,
|
||||
@required this.endDrawer,
|
||||
@required this.floatingActionButton,
|
||||
@required this.floatingActionButtonAnimator,
|
||||
@required this.floatingActionButtonLocation,
|
||||
@required this.persistentFooterButtons,
|
||||
@required this.primary,
|
||||
@required this.resizeToAvoidBottomInset,
|
||||
@required this.resizeToAvoidBottomPadding,
|
||||
@required this.scaffoldkey,
|
||||
@required this.detailScaffoldKey,
|
||||
@required this.nullItems,
|
||||
@required this.emptyItems,
|
||||
}) : childDelagate = SliverChildBuilderDelegate(
|
||||
itemBuilder,
|
||||
childCount: itemCount,
|
||||
addAutomaticKeepAlives: false,
|
||||
addRepaintBoundaries: false,
|
||||
addSemanticIndexes: false,
|
||||
),
|
||||
super(key: key);
|
||||
|
||||
TabletView.custom({
|
||||
Key key,
|
||||
@required this.slivers,
|
||||
@required this.detailBuilder,
|
||||
@required this.childDelagate,
|
||||
@required this.itemNotSelected,
|
||||
@required this.sideMenu,
|
||||
this.flexListView = 4,
|
||||
this.flexDetailView = 8,
|
||||
@required this.appBar,
|
||||
@required this.backgroundColor,
|
||||
@required this.bottomNavigationBar,
|
||||
@required this.bottomSheet,
|
||||
@required this.drawer,
|
||||
@required this.drawerDragStartBehavior,
|
||||
@required this.endDrawer,
|
||||
@required this.floatingActionButton,
|
||||
@required this.floatingActionButtonAnimator,
|
||||
@required this.floatingActionButtonLocation,
|
||||
@required this.persistentFooterButtons,
|
||||
@required this.primary,
|
||||
@required this.resizeToAvoidBottomInset,
|
||||
@required this.resizeToAvoidBottomPadding,
|
||||
@required this.scaffoldkey,
|
||||
@required this.detailScaffoldKey,
|
||||
@required this.nullItems,
|
||||
@required this.emptyItems,
|
||||
}) : super(key: key);
|
||||
|
||||
final List<Widget> slivers;
|
||||
final DetailWidgetBuilder detailBuilder;
|
||||
final Widget itemNotSelected;
|
||||
final Flexible sideMenu;
|
||||
final int flexListView;
|
||||
final int flexDetailView;
|
||||
final Widget nullItems, emptyItems;
|
||||
|
||||
final Widget floatingActionButton;
|
||||
|
||||
final FloatingActionButtonLocation floatingActionButtonLocation;
|
||||
|
||||
final Widget bottomNavigationBar;
|
||||
|
||||
final Widget bottomSheet;
|
||||
|
||||
final List<Widget> persistentFooterButtons;
|
||||
|
||||
final FloatingActionButtonAnimator floatingActionButtonAnimator;
|
||||
|
||||
final bool resizeToAvoidBottomPadding;
|
||||
|
||||
final bool resizeToAvoidBottomInset;
|
||||
|
||||
final bool primary;
|
||||
|
||||
final Key scaffoldkey, detailScaffoldKey;
|
||||
|
||||
// final bool extendBody;
|
||||
|
||||
final DragStartBehavior drawerDragStartBehavior;
|
||||
|
||||
final Color backgroundColor;
|
||||
|
||||
final PreferredSizeWidget appBar;
|
||||
|
||||
final Widget drawer, endDrawer;
|
||||
|
||||
final SliverChildDelegate childDelagate;
|
||||
|
||||
@override
|
||||
_TabletViewState createState() => _TabletViewState();
|
||||
}
|
||||
|
||||
class _TabletViewState extends State<TabletView> {
|
||||
int _index;
|
||||
|
||||
void reset() {
|
||||
setState(() {
|
||||
_index = 0;
|
||||
});
|
||||
}
|
||||
|
||||
// void update(DetailsScreen value) {
|
||||
// setState(() {
|
||||
// _index = value;
|
||||
// });
|
||||
// }
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: Flex(
|
||||
direction: Axis.horizontal,
|
||||
children: <Widget>[
|
||||
widget?.sideMenu ?? Container(),
|
||||
Flexible(
|
||||
flex: widget.flexListView,
|
||||
child: Scaffold(
|
||||
key: widget?.scaffoldkey,
|
||||
floatingActionButton: widget?.floatingActionButton,
|
||||
floatingActionButtonLocation:
|
||||
widget?.floatingActionButtonLocation,
|
||||
bottomNavigationBar: widget?.bottomNavigationBar,
|
||||
bottomSheet: widget?.bottomSheet,
|
||||
persistentFooterButtons: widget?.persistentFooterButtons,
|
||||
floatingActionButtonAnimator:
|
||||
widget?.floatingActionButtonAnimator,
|
||||
resizeToAvoidBottomInset: widget?.resizeToAvoidBottomInset,
|
||||
resizeToAvoidBottomPadding: widget?.resizeToAvoidBottomPadding,
|
||||
primary: widget?.primary,
|
||||
// extendBody: extendBody,
|
||||
backgroundColor: widget?.backgroundColor,
|
||||
drawer: widget?.drawer,
|
||||
endDrawer: widget?.endDrawer,
|
||||
appBar: widget?.appBar,
|
||||
body: CustomScrollView(
|
||||
slivers: <Widget>[]
|
||||
..addAll(widget.slivers ?? [])
|
||||
..add(Builder(
|
||||
builder: (BuildContext context) {
|
||||
SliverChildDelegate _childDelagate =
|
||||
widget?.childDelagate;
|
||||
if (_childDelagate?.estimatedChildCount == null &&
|
||||
widget?.nullItems != null)
|
||||
return SliverFillRemaining(child: widget.nullItems);
|
||||
if (_childDelagate?.estimatedChildCount != null &&
|
||||
_childDelagate.estimatedChildCount == 0 &&
|
||||
widget?.emptyItems != null)
|
||||
return SliverFillRemaining(child: widget.emptyItems);
|
||||
return SliverList(
|
||||
delegate: SliverChildBuilderDelegate(
|
||||
(BuildContext context, int index) {
|
||||
return new KeepAlive(
|
||||
keepAlive: true,
|
||||
child: new IndexedSemantics(
|
||||
index: index,
|
||||
child: GestureDetector(
|
||||
onTap: () {
|
||||
setState(() {
|
||||
_index = index;
|
||||
});
|
||||
},
|
||||
child: new Container(
|
||||
color: _index == index
|
||||
? Theme.of(context)
|
||||
.chipTheme
|
||||
.disabledColor
|
||||
: widget?.backgroundColor,
|
||||
padding:
|
||||
const EdgeInsets.symmetric(vertical: 8.0),
|
||||
child: _childDelagate.build(context, index),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
childCount: _childDelagate?.estimatedChildCount ?? 0,
|
||||
addAutomaticKeepAlives: false,
|
||||
addRepaintBoundaries: false,
|
||||
addSemanticIndexes: false,
|
||||
));
|
||||
},
|
||||
)),
|
||||
),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
flex: widget.flexDetailView,
|
||||
child: new _DetailView(
|
||||
detailScaffoldKey: widget?.detailScaffoldKey,
|
||||
details: _index == null ||
|
||||
_index > widget.childDelagate.estimatedChildCount - 1
|
||||
? null
|
||||
: widget.detailBuilder(context, _index, true),
|
||||
itemNotSelected: widget?.itemNotSelected,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _DetailView extends StatelessWidget {
|
||||
const _DetailView({
|
||||
Key key,
|
||||
@required DetailsScreen details,
|
||||
@required this.itemNotSelected,
|
||||
@required this.detailScaffoldKey,
|
||||
}) : _details = details,
|
||||
super(key: key);
|
||||
|
||||
final DetailsScreen _details;
|
||||
final Widget itemNotSelected;
|
||||
final Key detailScaffoldKey;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (_details == null) {
|
||||
return itemNotSelected ??
|
||||
Center(
|
||||
child: Text("No Item Selected"),
|
||||
);
|
||||
}
|
||||
return Scaffold(
|
||||
key: detailScaffoldKey,
|
||||
appBar: _details?.appBar,
|
||||
body: _details?.body,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user