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

我是研究僧i 提交于 2021-01-29 03:48:46

问题


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?

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.

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);
    }
  }
}

回答1:


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,
            ),
          ],
        ),
      ),
    );
  }
}



回答2:


What about having a Stack() with a ListView and then placing a Column with a Container placed at the bottom? It might isn't the answer you expect, but it works the way it's expected to. I tried thit:

Stack(
    children: <Widget>[
      ListView.builder(
        itemCount: 30,
        itemBuilder: (context, index) {
          return Container(
            child: Text(
                "Text\n"),
          );
        },
      ),
      Column(
        mainAxisAlignment: MainAxisAlignment.end,
        children: <Widget>[
          Container(
            width: double.infinity,
            height: 60,
            child: Text("That's the footer"),
            color: Colors.blue,
          ),
        ],
      )
    ],
  )



回答3:


Try this package

https://pub.dev/packages/sticky_infinite_list

In description there is a link to example app where you can play around with it.

This package supports sticky headers with top and bottom positioning also as left and right for both. It overlays content by default, but you can add margin to the bottom of your content, to prevent overlay and when header reaches it's min offset position




回答4:


Try Column with three children, Header and Footer have a specific size and ListView Occupies the remaining of the space.

        Column(
                children: [
                  Container(height: 100, child: HeaderWidget),
                  Expanded(child: ListView.builder(...)),
                  Container(height: 100, child: FooterWidget),
                ]

Scroll will be applied on the ListView.




回答5:


To implement such view i recommend using Slivers.

benefits:

  1. Sticky header/Footer.
  2. infinity body/content scroll.

check the code below:

import 'package:flutter/material.dart';

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomScrollView(
        slivers: [
          SliverList(
            delegate: SliverChildListDelegate(
              [
                Container(
                  width: double.infinity,
                  height: 50,
                  color: Colors.orangeAccent,
                  child: Center(
                    child: Text(
                      'Header',
                      style: TextStyle(color: Colors.white, letterSpacing:4),
                    ),
                  ),
                ),
                ListView.builder(
                  shrinkWrap: true,
                  itemCount: 100,
                  itemBuilder: (BuildContext context, int index) {
                    return ListTile(
                      title: Center(child: Text('$index')),
                    );
                  },
                ),
              ],
            ),
          ),
          SliverFillRemaining(
            hasScrollBody: false,
            child: Align(
              alignment: Alignment.bottomCenter,
              child: Container(
                width: double.infinity,
                height: 50,
                color: Colors.blueAccent,
                child: Center(
                  child: Text(
                    'Footer',
                    style: TextStyle(color: Colors.white, letterSpacing: 4),
                  ),
                ),
              ),
            ),
          )
        ],
      ),
    );
  }
}

For more detail take a look here:

https://itnext.io/create-a-header-footer-with-scrollable-body-view-in-flutter-5551087270de



来源:https://stackoverflow.com/questions/55862884/how-to-implement-position-sticky-and-bottom-0-with-flutter

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!