Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement position: sticky and bottom 0 with Flutter?

Tags:

flutter

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

enter image description here

In CSS,

.main-footer{     
     position: sticky; 
     bottom: 0;
}

but how to do with Flutter?

What I want

  1. Scrollable large content
  2. Footer (sticky)
  3. Scrollable large content

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.

enter image description here

code

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);
    }
  }
}
like image 465
Yuya Matsuo Avatar asked Oct 28 '25 17:10

Yuya Matsuo


1 Answers

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,
            ),
          ],
        ),
      ),
    );
  }
}
like image 67
Santosh Anand Avatar answered Oct 31 '25 11:10

Santosh Anand