Skip to content

Instantly share code, notes, and snippets.

@dirisujesse
Forked from jogboms/main.dart
Created February 9, 2020 07:20
Show Gist options
  • Save dirisujesse/2d6f9796a8abc451503524a7a03c3da2 to your computer and use it in GitHub Desktop.
Save dirisujesse/2d6f9796a8abc451503524a7a03c3da2 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.transparent,
elevation: 0,
),
body: ListView.builder(
itemBuilder: (context, _b) => ListTile(
title: Text(
'Hello, World!',
style: Theme.of(context).textTheme.headline1,
),
),
itemCount: 120,
),
),
);
}
}
enum _LayoutSlot {
body,
appBar,
background,
}
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,
// NOTE: FlutterLogo here can be replaced by anything
child: SizedBox.expand(child: FlutterLogo()),
),
LayoutId(
id: _LayoutSlot.body,
child: MediaQuery(
data: queryData.removePadding(removeBottom: false, 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);
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 - 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