Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.0k views
in Technique[技术] by (71.8m points)

dart - Listview with scrolling Footer at the bottom

I'm trying to create a scrolling list widgets which takes displays a few items and has the ability to add a footer at the bottom which scrolls along.

If the scrolling list doesn't take up the complete height, e.g. there are only 2 items, the footer should still appear at the bottom of the screen. Here are some sketches of what I'm trying to achieve

non page filling listview page filling listview

I tried calculating the vertical size that the listview needs but that'd mean that I need the know the height of the children at build time. Is there a better way?

EDIT
I'm trying to achieve the exact same thing as here but with Flutter of course.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

You will need to create a custom RenderBox for this. As there's no widgets which supports this out of the box.

SliverFillRemaining comes pretty close. But it's sizing/scrolling behavior is different then what you'd expect. As, if present, will almost always make the Scrollable... scrollable.

Instead, we can copy paste the sources of SliverFillRemaining. And make some edits

class SliverFooter extends SingleChildRenderObjectWidget {
  /// Creates a sliver that fills the remaining space in the viewport.
  const SliverFooter({
    Key key,
    Widget child,
  }) : super(key: key, child: child);

  @override
  RenderSliverFooter createRenderObject(BuildContext context) => new RenderSliverFooter();
}

class RenderSliverFooter extends RenderSliverSingleBoxAdapter {
  /// Creates a [RenderSliver] that wraps a [RenderBox] which is sized to fit
  /// the remaining space in the viewport.
  RenderSliverFooter({
    RenderBox child,
  }) : super(child: child);

  @override
  void performLayout() {
    final extent = constraints.remainingPaintExtent - math.min(constraints.overlap, 0.0);
    var childGrowthSize = .0; // added
    if (child != null) {
       // changed maxExtent from 'extent' to double.infinity
      child.layout(constraints.asBoxConstraints(minExtent: extent, maxExtent: double.infinity), parentUsesSize: true);
      childGrowthSize = constraints.axis == Axis.vertical ? child.size.height : child.size.width; // added
    }
    final paintedChildSize = calculatePaintOffset(constraints, from: 0.0, to: extent);
    assert(paintedChildSize.isFinite);
    assert(paintedChildSize >= 0.0);
    geometry = new SliverGeometry(
      // used to be this : scrollExtent: constraints.viewportMainAxisExtent,
      scrollExtent: math.max(extent, childGrowthSize),
      paintExtent: paintedChildSize,
      maxPaintExtent: paintedChildSize,
      hasVisualOverflow: extent > constraints.remainingPaintExtent || constraints.scrollOffset > 0.0,
    );
    if (child != null) {
      setChildParentData(child, constraints, geometry);
    }
  }
}

Here I changed one 3 things

  • Unconstrained the child maxExtent. Because if there's no more screen-space available, that would enforce a height of 0 to the footer.
  • changed SliverGeometry scrollExtent from "full screen height" to "actual available size". So that it actually only fill the remaining visible space. Not fill the screen.
  • added a minimum value to that same scrollExtent, equal to the actual footer height. So that if there's no more space remaining in the viewport, the children is simply added without any spacing around it.

We can now use it inside our CustomScrollView as usual.

End result :

new CustomScrollView(
  slivers: <Widget>[
    new SliverFixedExtentList(
      itemExtent: 42.0,
      delegate: new SliverChildBuilderDelegate((context, index) {
        return new SizedBox.expand(
          child: new Card(),
        );
      }, childCount: 42),
    ),
    new SliverFooter(
      child: new Align(
        alignment: Alignment.bottomCenter,
        child: new Container(
          height: 42.0,
          color: Colors.red,
        ),
      ),
    ),
  ],
),

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...