SliverAppBar不会完全折叠成短列表

时间:2019-03-25 21:54:42

标签: android dart flutter

我正在将Flutter的SliverAppBarSliverList一起使用。 应用程序栏可以很好地与长长的列表一起使用,滚动很多。 但是,如果我有8个项目的中型列表,则应用栏只会部分折叠,直到列表用完为止。从逻辑上讲,滚动停止是因为没有更多的项目,但它在应用栏上留下了非常讨厌的效果,该栏在过渡到折叠的工具栏的中间被留下。

有没有一种方法可以强制列表向上滚动直到工具栏完全折叠?

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton.extended(
        label: Text("Start!"),
        icon: Icon(Icons.play_arrow),
        backgroundColor: Colors.orange,
        elevation: 12,
        onPressed: () {
          Routing.navigate(
            context,
            LoggingPage(
              workout: _workout,
              exercises: workoutExercises,
            ),
          );
        },
      ),
      body: CustomScrollView( physics: ScrollPhysics(),
        slivers: <Widget>[
          SliverAppBar(
            actions: <Widget>[
              MaterialButton(onPressed: (){}, child: Text("data"),)
            ],
            expandedHeight: 300,
            pinned: true,
            floating: true,
            snap: true,
            flexibleSpace: FlexibleSpaceBar(
              title: Text(_workout.name),
            ),
          ),
          SliverList(
            delegate: SliverChildBuilderDelegate(
              buildSliverListItem,
              childCount: workoutExercises.length,
            ),
          ),
        ],
      ),
    );
  }

2 个答案:

答案 0 :(得分:0)

作为解决方法,您可以将窗口小部件与自定义RenderSliv​​er一起使用。必须将其添加到条状列表的末尾。

class CustomRenderSliver extends RenderSliver {
  final double _minHeaderHeight;
  final double _maxHeaderHeight;

  CustomRenderSliver(this._minHeaderHeight, this._maxHeaderHeight);

  @override
  void performLayout() {
    double maxHeight = this.constraints.viewportMainAxisExtent -
        (this.constraints.precedingScrollExtent - _maxHeaderHeight) /*height of regular list elements*/ -
        _minHeaderHeight;

    if (maxHeight < 0.0) maxHeight = 0.0;

    this.geometry = SliverGeometry(scrollExtent: maxHeight);
  }
}

list with custom sliver

完整代码

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';

void main() {
  final minHeaderHeight = 90.0;
  final maxHeaderHeight = 180.0;

  List<Widget> slivers = List.generate(4, (index) {
    return SliverToBoxAdapter(
      child: SizedBox(
        height: 100,
        child: Padding(
          padding: EdgeInsets.symmetric(vertical: 4),
          child: Container(
            color: Colors.blue,
          ),
        ),
      ),
    );
  });

  // header
  slivers.insert(
      0, SliverPersistentHeader(
    pinned: true,
    delegate: _SliverAppBarDelegate(
        minHeight: minHeaderHeight,
        maxHeight: maxHeaderHeight
    ),
  ));

  // custom sliver
  slivers.add(CustomRenderSliverWidget(minHeaderHeight, maxHeaderHeight));

  runApp(MaterialApp(
    home: CustomScrollView(
      slivers: slivers,
    ),
  ));
}

class CustomRenderSliverWidget extends LeafRenderObjectWidget {
  final double _minHeaderHeight;
  final double _maxHeaderHeight;

  CustomRenderSliverWidget(this._minHeaderHeight, this._maxHeaderHeight);

  @override
  RenderObject createRenderObject(BuildContext context) {
    return CustomRenderSliver(_minHeaderHeight, _maxHeaderHeight);
  }
}

class CustomRenderSliver extends RenderSliver {
  final double _minHeaderHeight;
  final double _maxHeaderHeight;

  CustomRenderSliver(this._minHeaderHeight, this._maxHeaderHeight);

  @override
  void performLayout() {
    double maxHeight = this.constraints.viewportMainAxisExtent -
        (this.constraints.precedingScrollExtent - _maxHeaderHeight) /*height of regular list elements*/ -
        _minHeaderHeight;

    if (maxHeight < 0.0) maxHeight = 0.0;

    this.geometry = SliverGeometry(scrollExtent: maxHeight);
  }
}

class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
  _SliverAppBarDelegate({
    @required this.minHeight,
    @required this.maxHeight,
  });

  final double minHeight;
  final double maxHeight;

  @override
  double get minExtent => minHeight;

  @override
  double get maxExtent => max(maxHeight, minHeight);

  @override
  Widget build(BuildContext context, double shrinkOffset,
      bool overlapsContent) {
    return Container(color: Colors.red,);
  }

  @override
  bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
    return maxHeight != oldDelegate.maxHeight ||
        minHeight != oldDelegate.minHeight;
  }
}

答案 1 :(得分:0)

我们可以使用基于代码的 NestedScrollView、SliverOverlapAbsorber 和 SliverOverlapInjector,这里有 Andrea 的例子

https://github.com/bizz84/slivers_demo_flutter/blob/master/lib/pages/nested_scroll_view_page.dart

我们使用 NestedScrollView。首先,我们将 SliverAppbar 嵌入到 headerSliv​​erBuilder 中,并在 SliverAppBar 上方使用 SliverOverlapAbsorber。

接下来,我们将 CustomScrollView 嵌入到 NestedScrollView 主体内的构建器中。我们在主体顶部添加了一个 SliverOverlapInjector。

return Scaffold(
      body: NestedScrollView(
        headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled){
          return <Widget>[
            SliverOverlapAbsorber(
              handle:
              NestedScrollView.sliverOverlapAbsorberHandleFor(context),
              sliver: SliverAppBar(

                pinned: true,
                //floating: true,
                stretch: true,
                expandedHeight: 300.0,
                flexibleSpace: FlexibleSpaceBar(
                  centerTitle: true,
                  title: const Text('Weather Report'),
                  background: Image.asset(
                    'assets/images/logo1.jpg',
                    fit: BoxFit.cover,
                  ),
                ),
              ),
            ),
          ];
        },
        body: SafeArea(
          child: Builder(
              builder:(BuildContext context) {
                return CustomScrollView(
                  slivers: <Widget>[
                    SliverOverlapInjector(
                      // This is the flip side of the SliverOverlapAbsorber above.
                      handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
                          context),
                    ),
                    SliverList(
                      delegate: SliverChildBuilderDelegate(
                          (BuildContext context, int i){
                            return ListTile(
                              leading: Icon(Icons.wb_sunny),
                              title: i%2 != 1 ? Text('Sunday ${i+1}') : Text('Monday ${i+1}'),
                              subtitle: Text('sunny, h: 80, l: 65'),
                            );
                          },
                        childCount: 5
                      ),
                    ),

                  ],
                );
              }
          ),
        ),
      ),
    );

enter image description here