I want to build a list view with sticky footer like this article's "Stick to the bottom?!" in Flutter.

In CSS,
.main-footer{
position: sticky;
bottom: 0;
}
but how to do with Flutter?
1 and 2 are visible at First (Scrollable content and fixed footer). After scroll to end of 1, Footer (2) become not fixed. Rest of contents (3) will be shown below footer(2).
I tried to implement above with CustomScrollView but footer button is not drawn above list.

import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Fixed footer',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
body: _FixedFooterDemo(),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.add),
),
),
);
}
}
class _FixedFooterDemo extends StatelessWidget {
const _FixedFooterDemo({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: <Widget>[
SliverAppBar(
title: Text('Fixed footer'),
),
SliverList(
delegate: SliverChildListDelegate(List.generate(20, _buildListItem)),
),
SliverStickyFooter(
child: Center(
child: RaisedButton(
onPressed: () {},
child: Text('Fixed under list button'),
),
),
),
SliverFillRemaining(
child: Container(
color: Colors.yellow,
child: Center(
child: Text('below space'),
),
),
),
],
);
}
ListTile _buildListItem(int i) {
return ListTile(
title: Text(
'Item $i',
),
subtitle: Text(
'Sit est ipsum consequat sit ex. Minim magna laborum dolore aliqua sit dolore velit sint fugiat. Culpa officia tempor proident minim aliquip nisi reprehenderit ullamco duis mollit. Aute velit irure ut Lorem pariatur anim mollit cillum dolor irure quis. Eu officia dolore deserunt do est cupidatat duis elit. Pariatur magna reprehenderit aliquip ea irure Lorem sunt aute.',
maxLines: 2,
),
);
}
}
class SliverStickyFooter extends SingleChildRenderObjectWidget {
const SliverStickyFooter({
Key key,
Widget child,
}) : super(key: key, child: child);
@override
RenderSliverStickyFooter createRenderObject(BuildContext context) =>
RenderSliverStickyFooter();
}
class RenderSliverStickyFooter extends RenderSliverSingleBoxAdapter {
/// Creates a [RenderSliver] that wraps a [RenderBox] which is sized to fit
/// the remaining space in the viewport.
RenderSliverStickyFooter({
RenderBox child,
}) : super(child: child);
@override
void performLayout() {
child?.layout(
constraints.asBoxConstraints(),
parentUsesSize: true,
);
final paintedChildSize =
calculatePaintOffset(constraints, from: 0.0, to: child.size.height);
assert(paintedChildSize.isFinite);
assert(paintedChildSize >= 0.0);
geometry = SliverGeometry(
scrollExtent: child.size.height,
paintExtent: paintedChildSize,
maxPaintExtent: paintedChildSize,
hasVisualOverflow: true,
paintOrigin: -child.size.height + paintedChildSize,
visible: true,
);
if (child != null) {
setChildParentData(child, constraints, geometry);
}
}
}
Try this
import 'package:flutter/material.dart';
class Sticky extends StatefulWidget {
Sticky({Key key}) : super(key: key);
_StickyState createState() => _StickyState();
}
class _StickyState extends State<Sticky> {
@override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Stack(
children: <Widget>[
Positioned(
child: Container(
color: Colors.black38,
height: 60,
width: MediaQuery.of(context).size.width,
child: Text('Header'),
),
top: 0,
),
Positioned(
child: Container(
child: Text('Content'),
),
top: 60,
),
Positioned(
child: Container(
color: Colors.black38,
height: 60,
width: MediaQuery.of(context).size.width,
child: Text('Footer'),
),
bottom: 0,
),
],
),
),
);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With