Skip to content

Instantly share code, notes, and snippets.

@jogboms
Last active June 20, 2020 13:26
Show Gist options
  • Save jogboms/73e2488362f3d6f27ecc7e73fe32a358 to your computer and use it in GitHub Desktop.
Save jogboms/73e2488362f3d6f27ecc7e73fe32a358 to your computer and use it in GitHub Desktop.
A simple CustomMultiChildLayout
import 'package:flutter/material.dart';
final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
debugShowCheckedModeBanner: false,
home: AppLayout(
appBar: AppBar(
title: Text("Hello World"),
backgroundColor: Colors.red.shade400.withOpacity(.5),
),
body: ListView.builder(
itemBuilder: (context, index) => ListTile(
title: Text('$index', style: Theme.of(context).textTheme.headline6),
),
itemCount: 120,
),
),
);
}
}
enum _LayoutSlot {
body,
appBar,
background,
overlay,
}
class AppLayout extends StatelessWidget {
const AppLayout({
Key key,
@required this.body,
this.appBar,
this.padding,
}) : super(key: key);
final PreferredSizeWidget appBar;
final Widget body;
final EdgeInsets padding;
@override
Widget build(BuildContext context) {
final queryData = MediaQuery.of(context);
final systemPadding = queryData.padding;
final appBarHeight = appBar != null ? appBar.preferredSize.height + systemPadding.top : 0.0;
return Material(
child: CustomMultiChildLayout(
delegate: _AppLayoutDelegate(viewInsets: queryData.viewInsets),
children: <Widget>[
LayoutId(
id: _LayoutSlot.background,
child: SizedBox.expand(
child: Image.network(
"https://r1.ilikewallpaper.net/iphone-8-wallpapers/download/28792/Abstract-Colorful-Square-Overlap-iphone-8-wallpaper-ilikewallpaper_com.jpg",
),
),
),
LayoutId(
id: _LayoutSlot.overlay,
child: SizedBox.expand(child: ColoredBox(color: Colors.black45)),
),
LayoutId(
id: _LayoutSlot.body,
child: MediaQuery(
data: queryData.removePadding(removeTop: appBar != null),
child: body,
),
),
if (appBar != null)
LayoutId(
id: _LayoutSlot.appBar,
child: ConstrainedBox(
constraints: BoxConstraints(maxHeight: appBarHeight),
child: FlexibleSpaceBar.createSettings(
currentExtent: appBarHeight,
child: MediaQuery(
data: queryData.removePadding(removeBottom: true),
child: appBar,
),
),
),
),
],
),
);
}
}
class _AppLayoutDelegate extends MultiChildLayoutDelegate {
_AppLayoutDelegate({this.viewInsets});
final EdgeInsets viewInsets;
@override
void performLayout(Size size) {
final looseConstraints = BoxConstraints.loose(size);
final fullWidthConstraints = looseConstraints.tighten(width: size.width);
layoutChild(_LayoutSlot.background, fullWidthConstraints);
positionChild(_LayoutSlot.background, Offset.zero);
layoutChild(_LayoutSlot.overlay, fullWidthConstraints);
positionChild(_LayoutSlot.overlay, Offset.zero);
double appBarHeight = 0.0;
if (hasChild(_LayoutSlot.appBar)) {
appBarHeight =
layoutChild(_LayoutSlot.appBar, fullWidthConstraints).height;
positionChild(_LayoutSlot.appBar, Offset.zero);
}
final bodyConstraints = fullWidthConstraints.copyWith(
maxHeight:
fullWidthConstraints.maxHeight - appBarHeight - viewInsets.bottom,
);
layoutChild(_LayoutSlot.body, bodyConstraints);
positionChild(_LayoutSlot.body, Offset(0, appBarHeight));
}
@override
bool shouldRelayout(_AppLayoutDelegate oldDelegate) =>
viewInsets != oldDelegate.viewInsets;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment