Git Product home page Git Product logo

fluttercandies / extended_nested_scroll_view Goto Github PK

View Code? Open in Web Editor NEW
593.0 6.0 120.0 2.83 MB

extended nested scroll view to fix following issues. 1.pinned sliver header issue 2.inner scrollables in tabview sync issue 3.pull to refresh is not work. 4.do without ScrollController in NestedScrollView's body

License: MIT License

Dart 99.02% Ruby 0.98%
pinned-sliver-headers nestedscrollview flutter tabview-sync-issue

extended_nested_scroll_view's Introduction

extended_nested_scroll_view's People

Contributors

alexv525 avatar ponycui avatar yrom avatar zmtzawqlp avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

extended_nested_scroll_view's Issues

并不能完全解决多Tab滚动联动问题

只有当完全滚动至第二个TabView后, 才能"解除"多Tab的滚动联动问题

具体可以看附件内录制的视频

Kapture 2020-07-10 at 18.53.08.mp4.zip

插件版本号 1.0.1

flutter: 1.17.3

代码:

import 'package:flutter/material.dart' hide NestedScrollView;
import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  TabController tc;
  @override
  void initState() {
    super.initState();
    tc = TabController(length: 4, vsync: this);
    tc.addListener(() {
      index = tc.index;
    });
  }

  int index;

  @override
  void dispose() {
    tc.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 4,
      child: Scaffold(
        body: NestedScrollView(
          headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
            return [
              SliverAppBar(
                pinned: true,
                floating: true,
                forceElevated: innerBoxIsScrolled,
                expandedHeight: 210.0,
                flexibleSpace: FlexibleSpaceBar(
                  title: Text('你好'),
                  background: Container(
                    child: Text('我是内容'),
                  ),
                ),
              ),
            ];
          },
          innerScrollPositionKeyBuilder: () {
            return Key(index.toString());
          },
          body: TabBarView(
            controller: tc,
            children: [
              _buildList(tc, 0),
              _buildList(tc, 1),
              _buildList(tc, 2),
              _buildList(tc, 3),
            ],
          ),
        ),
      ),
    );
  }

  _buildList(TabController tc, int index) {
    return Content(index: index);
  }
}

class Content extends StatefulWidget {
  final int index;

  const Content({
    Key key,
    this.index,
  }) : super(key: key);

  @override
  ContentState createState() => ContentState();
}

class ContentState extends State<Content> with AutomaticKeepAliveClientMixin {
  Key key;

  @override
  void initState() {
    key = Key(widget.index.toString());
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return NotificationListener<ScrollNotification>(
      onNotification: (notification) {
        return true;
      },
      child: NestedScrollViewInnerScrollPositionKeyWidget(
        key,
        ListView.builder(
          itemBuilder: (context, index) {
            return ListTile(
              title: Text(index.toString()),
            );
          },
        ),
      ),
    );
  }

  @override
  bool get wantKeepAlive => true;
}

compile on beta lastest version post a error

../../.pub-cache/hosted/pub.flutter-io.cn/extended_nested_scroll_view-0.4.0/lib/src/old_extended_nested_scroll_view.dart:1069:7: Error: The non-abstract class '_NestedScrollPosition' is missing implementations for these members:

  • ScrollPosition.pointerScroll
    flutter doctor -v:
    [✓] Flutter (Channel beta, 1.26.0-17.6.pre, on Mac OS X 10.15.5 19F101 darwin-x64, locale zh-Hans-CN)
    • Flutter version 1.26.0-17.6.pre at /Users/liuyanfeng/Library/flutter
    • Framework revision a29104a69b (3 days ago), 2021-02-16 09:26:56 -0800
    • Engine revision 21fa8bb99e
    • Dart version 2.12.0 (build 2.12.0-259.12.beta)
    • Pub download mirror https://pub.flutter-io.cn
    • Flutter download mirror https://storage.flutter-io.cn

列表滚动同步,好像不行了

Flutter:1.7.8+hotfix.3
extended_nexsted_scroll_view 0.3.6
使用TabBar与PageView搭配使用,放PageView存放GridView,已经使用NestedScrollViewInnerScrollPositionKeyWidget和给定不同的key

Null Safety causes a problem

Hi! Thank you for making this package available.
I have an urgent situation and need to implement a code by using this package. However, because of the new null safety migration (I think), it gives an error.

Here is the error stack:

The relevant error-causing widget was      NestedScrollView   lib/…/multiviewer/multi-tab-view.dart:34

When the exception was thrown, this was the stack

#0      ScrollPosition.pixels    package:flutter/…/widgets/scroll_position.dart:166

#1      new _NestedScrollPosition    package:extended_nested_scroll_view/src/old_extended_nested_scroll_view.dart:1163

#2      _NestedScrollController.createScrollPosition     package:extended_nested_scroll_view/src/old_extended_nested_scroll_view.dart:1029

#3      ScrollableState._updatePosition     package:flutter/…/widgets/scrollable.dart:406

#4      ScrollableState.didChangeDependencies    package:flutter/…/widgets/scrollable.dart:432
...
════════════════════════════════════════════════════════════════════════════════

Fixing Vertical viewport was given unbounded height.

how can i put this library into CustomScrollView? i get this error:

Vertical viewport was given unbounded height.

i used the library sample code and added CustomScrollView to parent of NestedScrollViewRefreshIndicator

return CustomScrollView(
  physics: const ClampingScrollPhysics(),
  slivers: <Widget>[
    SliverPadding(
      padding: const EdgeInsets.all(0),
      sliver: SliverList(
        delegate: SliverChildListDelegate([
          NestedScrollViewRefreshIndicator(
            onRefresh: onRefresh,
            child: NestedScrollView(
                headerSliverBuilder: (BuildContext c, bool f) {
                  return buildSliverHeader();
                },
                //1.[pinned sliver header issue](https://github.com/flutter/flutter/issues/22393)
                pinnedHeaderSliverHeightBuilder: () {
                  return pinnedHeaderHeight;
                },
                //2.[inner scrollables in tabview sync issue](https://github.com/flutter/flutter/issues/21868)
                innerScrollPositionKeyBuilder: () {
                  String index = 'Tab';
                  if (primaryTC.index == 0) {
                    index +=
                        primaryTC.index.toString() + secondaryTC.index.toString();
                  } else {
                    index += primaryTC.index.toString();
                  }
                  return Key(index);
                },
                body: Column(
                  children: <Widget>[
                    TabBar(
                      controller: primaryTC,
                      labelColor: Colors.blue,
                      indicatorColor: Colors.blue,
                      indicatorSize: TabBarIndicatorSize.label,
                      indicatorWeight: 2.0,
                      isScrollable: false,
                      unselectedLabelColor: Colors.grey,
                      tabs: const <Tab>[
                        Tab(text: 'Tabqq0'),
                        Tab(text: 'Tab1'),
                      ],
                    ),
                    Expanded(
                      child: TabBarView(
                        controller: primaryTC,
                        children: <Widget>[
                          SecondaryTabView('Tab0', secondaryTC, true),
                          NestedScrollViewInnerScrollPositionKeyWidget(
                            const Key('Tab1'),
                            GlowNotificationWidget(
                              ListView.builder(
                                //store Page state
                                key: const PageStorageKey<String>('Tab1'),
                                physics: const ClampingScrollPhysics(),
                                itemBuilder: (BuildContext c, int i) {
                                  return Container(
                                    alignment: Alignment.center,
                                    height: 60.0,
                                    child: Text(const Key('Tab1').toString() +
                                        ': ListView$i'),
                                  );
                                },
                                itemCount: 50,
                              ),
                              showGlowLeading: false,
                            ),
                          )
                        ],
                      ),
                    )
                  ],
                )),
          )
        ]),
      ),
    )
  ],
);

Update documentation on the 2.0.0 breaking changes

I noticed that the library was upgraded to 2.0.0 version a couple of days ago. This update introducing 2 breaking changes but I can't find any information about them. Can you update it in the document?

How to make TabBar pin at the top?

Previously, i use SliverPersistentHeader for Pinned header.

But, for your example, you don't use SliverPersistentHeader. So, how do you do that?

Tab切换滚动高度重置问题

请教一个extended_nested_scroll_view的问题,tab0滚动一部分,切换到tab1在滚动一部分,然后tab1直接滚动到顶部,tab0如何重置滚动高度,现在是tab0没有跟随滚动,还是原来的滚动位置。

问题展示

期望效果

操作后 切换到Tab0滚动高度为0

实际效果

操作后 切换到Tab0滚动高度未重置

flutter doctor

image

代码

import 'dart:async';
import 'dart:math';
import 'package:flutter/material.dart'
    hide NestedScrollView, NestedScrollViewState;
import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:loading_more_list/loading_more_list.dart';

class TabList3Demo extends StatefulWidget {
  @override
  _TabList3DemoState createState() => _TabList3DemoState();
}

class _TabList3DemoState extends State<TabList3Demo>
    with TickerProviderStateMixin {
  TabController primaryTC;
  final GlobalKey<NestedScrollViewState> _key =
      GlobalKey<NestedScrollViewState>();
  @override
  void initState() {
    primaryTC = TabController(length: 2, vsync: this);
    super.initState();
  }

  @override
  void dispose() {
    primaryTC.dispose();
    super.dispose();
  }

  Future _onRefresh() async {
    await Future.delayed(Duration(seconds: 1), () {
      print('refresh');
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: _buildScaffoldBody(),
    );
  }

  Widget _buildScaffoldBody() {
    final double statusBarHeight = MediaQuery.of(context).padding.top;
    final double pinnedHeaderHeight =
        //statusBar height
        statusBarHeight +
            //pinned SliverAppBar height in header
            kToolbarHeight;
    return NestedScrollViewRefreshIndicator(
      onRefresh: _onRefresh,
      child: NestedScrollView(
        key: _key,
        headerSliverBuilder: (BuildContext c, bool f) {
          return <Widget>[
            SliverAppBar(
              pinned: true,
              expandedHeight: 200.0,
              title: const Text('load more list'),
              flexibleSpace: FlexibleSpaceBar(
                collapseMode: CollapseMode.pin,
                background: Image.asset(
                  'images/[email protected]',
                  fit: BoxFit.fill,
                ),
              ),
            ),
            SliverToBoxAdapter(child: Container(height: 200,child: Text('王老吉'),),),
            SliverToBoxAdapter(child: Container(height: 200,child: Text('加多宝'),),),
            SliverToBoxAdapter(child: Container(height: 200,child: Text('和其正'),),),
          ];
        },
        //1.[pinned sliver header issue](https://github.com/flutter/flutter/issues/22393)
        pinnedHeaderSliverHeightBuilder: () {
          return pinnedHeaderHeight;
        },
        //2.[inner scrollables in tabview sync issue](https://github.com/flutter/flutter/issues/21868)
        innerScrollPositionKeyBuilder: () {
          String index = 'Tab';

          index += primaryTC.index.toString();

          return Key(index);
        },
        body: Column(
          children: <Widget>[
            TabBar(
              controller: primaryTC,
              labelColor: Theme.of(context).primaryColor,
              indicatorSize: TabBarIndicatorSize.label,
              indicatorWeight: 2.0,
              labelStyle: TextStyle(fontSize: 22, fontWeight: FontWeight.w500),
              isScrollable: false,
              unselectedLabelColor: Colors.grey,
              tabs: const <Tab>[
                Tab(text: 'Tab0'),
                Tab(text: 'Tab1'),
              ],
            ),
            Expanded(
              child: TabBarView(
                controller: primaryTC,
                children: const <Widget>[
                  TabViewItem(Key('Tab0')),
                  TabViewItem(Key('Tab1')),
                ],
              ),
            )
          ],
        ),
      ),
    );
  }
}

class LoadMoreListSource extends LoadingMoreBase<int> {
  bool _hasMore = true;
  @override
  bool get hasMore => _hasMore;
  @override
  Future<bool> loadData([bool isloadMoreAction = false]) {
    return Future<bool>.delayed(const Duration(seconds: 1), () {
      for (int i = 0; i < 10; i++) {
        this.add(Random().nextInt(400));
      }
      return true;
    });
  }
}

class TabViewItem extends StatefulWidget {
  const TabViewItem(this.tabKey);
  final Key tabKey;
  @override
  _TabViewItemState createState() => _TabViewItemState();
}

class _TabViewItemState extends State<TabViewItem>
    with AutomaticKeepAliveClientMixin {
  LoadMoreListSource source;
  @override
  void initState() {
    source = LoadMoreListSource();
    super.initState();
  }

  @override
  void dispose() {
    source.dispose();
    super.dispose();
  }

  Widget _buildIndicator(BuildContext context, IndicatorStatus status) {
    Widget widget;
    switch (status) {
      case IndicatorStatus.fullScreenBusying:
        widget = SpinKitFadingCube(
          color: Theme.of(context).primaryColor,
          size: 40.0,
        );
        break;
      case IndicatorStatus.loadingMoreBusying:
        widget = SpinKitThreeBounce(
          color: Theme.of(context).primaryColor,
          size: 40.0,
        );
        break;
      default:
    }
    return widget;
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);
    final LoadingMoreList<int> child = LoadingMoreList<int>(
      ListConfig<int>(
        physics: const ClampingScrollPhysics(),
        indicatorBuilder: _buildIndicator,
        itemBuilder: (BuildContext c, int item, int index) {
          return GestureDetector(
            onTap: () {
              source.remove(item);
              source.setState();
            },
            child: Container(
              alignment: Alignment.center,
              height: 60.0,
              child: Text(
                  widget.tabKey.toString() + ': ListView${item.toString()}'),
            ),
          );
        },
        sourceList: source,
      ),
    );

    return NestedScrollViewInnerScrollPositionKeyWidget(widget.tabKey, child);
  }

  @override
  bool get wantKeepAlive => true;
}

置顶时候内存激增

class A extends StatelessWidget {
  final GlobalKey<extended.NestedScrollViewState> globalKey =
      GlobalKey<extended.NestedScrollViewState>();
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          globalKey.currentState.currentInnerPosition.jumpTo(0.0);
        },
      ),
      body: extended.NestedScrollView(
        key: globalKey,
        innerScrollPositionKeyBuilder: () {
          return Key('Nest-1-0');
        },
        headerSliverBuilder: (
          BuildContext context,
          bool innerBoxIsScrolled,
        ) {
          final List<Widget> widgets = <Widget>[];
          return widgets;
        },
        body: extended.NestedScrollViewInnerScrollPositionKeyWidget(
          Key('Nest-1-0'),
          CustomScrollView(
            slivers: [
              SliverList(
                delegate: SliverChildBuilderDelegate(
                  (context, index) {
                    print(index);
                    return Image.network(
                      'https://picsum.photos/seed/${Random().nextInt(99999)}/500/500',
                      height: 500,
                    );
                  },
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

上述代码, 在滑动到比较底部的时候,点击置顶, 会出现内存激增的状况, 如果列表很长, 就会崩溃, 有没有什么别的办法,能解决这个问题吗, 如果不用动画, 我用动画如果时间设置较长才会没有这个问题.
截屏2020-08-18 下午8 24 27
这是ios的监控图 后面那段比较高的就是我点击了置顶

滚动操作无法传递到 body

extended.NestedScrollView 中设置了 controller 之后,调用 controller.jumpTo(offset),如果 offset 超过了 headerSliverBuilder 定义的 expandedHeight,则只会滚动到 expandedHeight,不会继续去操作 body 中的滚动。

且由于你的库中,对 body 中的控件设置了 controller,外部也已经不能再设置别的 controller 来进行控制了。

动态更改 pinned header 高度后立即滑动会出现报错,报错之后导致列表非常卡顿

动态更改 pinned header 高度,比如 初始高度为 100,更改为500后,立刻滑动列表,则会触发以下报错,如果继续滑动会不断抛出异常,导致滑动非常卡顿。

如果更改完500后,等待 1 秒再滑动列表,则不会报错,我怀疑在设置完高度后不是立即生效的,而是有一个过渡,如果在过渡时间内滑动列表则会导致报错。

错误日志:

I/flutter (18969): ══╡ EXCEPTION CAUGHT BY RENDERING LIBRARY ╞═════════════════════════════════════════════════════════
I/flutter (18969): The following assertion was thrown during performLayout():
I/flutter (18969): 'package:extended_nested_scroll_view/src/old_extended_nested_scroll_view.dart': Failed assertion:
I/flutter (18969): line 696 pos 16: 'extra >= 0.0': is not true.
I/flutter (18969):
I/flutter (18969): The relevant error-causing widget was:
I/flutter (18969):   NestedScrollViewViewport
I/flutter (18969):   file:///D:/office/flutter/.pub-cache/hosted/pub.flutter-io.cn/extended_nested_scroll_view-0.4.0/lib/src/old_extended_nested_scroll_view.dart:416:12
I/flutter (18969):
I/flutter (18969): When the exception was thrown, this was the stack:
I/flutter (18969): #2      _NestedScrollCoordinator._getMetrics (package:extended_nested_scroll_view/src/old_extended_nested_scroll_view.dart:696:16)
I/flutter (18969): #3      _NestedScrollCoordinator.createOuterBallisticScrollActivity (package:extended_nested_scroll_view/src/old_extended_nested_scroll_view.dart:644
:42)
I/flutter (18969): #4      _NestedOuterBallisticScrollActivity.applyNewDimensions (package:extended_nested_scroll_view/src/old_extended_nested_scroll_view.dart:1407:21)
I/flutter (18969): #5      ScrollPosition.applyNewDimensions (package:flutter/src/widgets/scroll_position.dart:524:14)
I/flutter (18969): #6      _NestedScrollPosition.applyNewDimensions (package:extended_nested_scroll_view/src/old_extended_nested_scroll_view.dart:1322:11)
I/flutter (18969): #7      ScrollPosition.applyContentDimensions (package:flutter/src/widgets/scroll_position.dart:495:7)
I/flutter (18969): #8      _NestedScrollPosition.applyContentDimensions (package:extended_nested_scroll_view/src/old_extended_nested_scroll_view.dart:1129:18)
I/flutter (18969): #9      RenderViewport.performLayout (package:flutter/src/rendering/viewport.dart:1357:20)
I/flutter (18969): #10     RenderObject._layoutWithoutResize (package:flutter/src/rendering/object.dart:1630:7)
I/flutter (18969): #11     PipelineOwner.flushLayout (package:flutter/src/rendering/object.dart:887:18)
I/flutter (18969): #12     RendererBinding.drawFrame (package:flutter/src/rendering/binding.dart:402:19)
I/flutter (18969): #13     WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:884:13)
I/flutter (18969): #14     RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:284:5)
I/flutter (18969): #15     SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1113:15)
I/flutter (18969): #16     SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1052:9)
I/flutter (18969): #17     SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:968:5)
I/flutter (18969): #21     _invoke (dart:ui/hooks.dart:261:10)
I/flutter (18969): #22     _drawFrame (dart:ui/hooks.dart:219:3)
I/flutter (18969): (elided 5 frames from class _AssertionError and dart:async)
I/flutter (18969):
I/flutter (18969): The following RenderObject was being processed when the exception was fired: RenderNestedScrollViewViewport#543b9 NEEDS-LAYOUT NEEDS-PAINT:
I/flutter (18969):   needs compositing
I/flutter (18969):   creator: NestedScrollViewViewport ← IgnorePointer-[GlobalKey#d268c] ← Semantics ← _PointerListener ←
I/flutter (18969):     Listener ← _GestureSemantics ←
I/flutter (18969):     RawGestureDetector-[LabeledGlobalKey<RawGestureDetectorState>#859ed] ← _PointerListener ← Listener
I/flutter (18969):     ← _ScrollableScope ← _ScrollSemantics-[GlobalKey#a3f14] ← RepaintBoundary ← ⋯
I/flutter (18969):   parentData: <none> (can use size)
I/flutter (18969):   constraints: BoxConstraints(0.0<=w<=360.0, 0.0<=h<=751.7)
I/flutter (18969):   layer: OffsetLayer#e6444
I/flutter (18969):   size: Size(360.0, 751.7)
I/flutter (18969):   axisDirection: down
I/flutter (18969):   crossAxisDirection: right
I/flutter (18969):   offset: _NestedScrollPosition#36a6d(outer, offset: 324.1, range: 0.0..0.0, viewport: 751.7)
I/flutter (18969):   anchor: 0.0
I/flutter (18969):   handle: SliverOverlapAbsorberHandle(null, orphan)
I/flutter (18969): This RenderObject had the following descendants (showing up to depth 5):
I/flutter (18969):     center child: _RenderSliverPinnedPersistentHeaderForWidgets#c6939 relayoutBoundary=up1 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
I/flutter (18969):       child: RenderSemanticsAnnotations#3cfb1 relayoutBoundary=up2 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
I/flutter (18969):         child: RenderAnnotatedRegion<SystemUiOverlayStyle>#6113e relayoutBoundary=up3 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
I/flutter (18969):           child: RenderPhysicalModel#124c0 relayoutBoundary=up4 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
I/flutter (18969):             child: _RenderInkFeatures#9d69f relayoutBoundary=up5 NEEDS-PAINT NEEDS-COMPOSITING-BITS-UPDATE
I/flutter (18969):     child 1: RenderSliverFillRemainingWithScrollable#ba2ba relayoutBoundary=up1 NEEDS-PAINT
I/flutter (18969):       child: RenderStack#52f1d NEEDS-PAINT
I/flutter (18969):         child 1: RenderFlex#80e0d relayoutBoundary=up1 NEEDS-PAINT
I/flutter (18969):           child 1: RenderDecoratedBox#acb5c relayoutBoundary=up2
I/flutter (18969):             child: RenderPadding#a6c84 relayoutBoundary=up3
I/flutter (18969):           child 2: RenderRepaintBoundary#e0363 relayoutBoundary=up2 NEEDS-PAINT
I/flutter (18969):             child: RenderCustomPaint#71b77 relayoutBoundary=up3 NEEDS-PAINT
I/flutter (18969):         child 2: _RenderLayoutBuilder#fd219 relayoutBoundary=up1 NEEDS-PAINT
I/flutter (18969):           child: RenderConstrainedBox#432d0 relayoutBoundary=up2 NEEDS-PAINT
I/flutter (18969): ════════════════════════════════════════════════════════════════════════════════════════════════════
I/flutter (18969): Another exception was thrown: 'package:extended_nested_scroll_view/src/old_extended_nested_scroll_view.dart': Failed assertion: line 725 pos 16: 'ext
ra <= 0.0': is not true.
I/flutter (18969): Another exception was thrown: 'package:flutter/src/widgets/scrollable.dart': Failed assertion: line 525 pos 12: '_drag == null': is not true.
I/flutter (18969): Another exception was thrown: 'package:flutter/src/widgets/scrollable.dart': Failed assertion: line 534 pos 12: '_drag == null': is not true.
W/HiTouch_PressGestureDetector(18969): Touch pointer move a lot. The moving distance of X is:56.0, limit is:60The moving distance of Y is:85.0, limit is:60
I/flutter (18969): Another exception was thrown: 'package:extended_nested_scroll_view/src/old_extended_nested_scroll_view.dart': Failed assertion: line 725 pos 16: 'ext
ra <= 0.0': is not true.
I/flutter (18969): Another exception was thrown: 'package:flutter/src/widgets/scrollable.dart': Failed assertion: line 525 pos 12: '_drag == null': is not true.
I/flutter (18969): Another exception was thrown: 'package:flutter/src/widgets/scrollable.dart': Failed assertion: line 534 pos 12: '_drag == null': is not true.
W/HiTouch_PressGestureDetector(18969): Touch pointer move a lot. The moving distance of X is:11.0, limit is:60The moving distance of Y is:74.0, limit is:60
I/flutter (18969): Another exception was thrown: 'package:extended_nested_scroll_view/src/old_extended_nested_scroll_view.dart': Failed assertion: line 696 pos 16: 'ext
ra >= 0.0': is not true.
I/flutter (18969): Another exception was thrown: 'package:flutter/src/widgets/scrollable.dart': Failed assertion: line 525 pos 12: '_drag == null': is not true.
I/flutter (18969): Another exception was thrown: 'package:flutter/src/widgets/scrollable.dart': Failed assertion: line 534 pos 12: '_drag == null': is not true.
W/HiTouch_PressGestureDetector(18969): Touch pointer move a lot. The moving distance of X is:71.0, limit is:60The moving distance of Y is:107.0, limit is:60
I/flutter (18969): Another exception was thrown: 'package:extended_nested_scroll_view/src/old_extended_nested_scroll_view.dart': Failed assertion: line 725 pos 16: 'ext
ra <= 0.0': is not true.
I/flutter (18969): Another exception was thrown: 'package:flutter/src/widgets/scrollable.dart': Failed assertion: line 525 pos 12: '_drag == null': is not true.
I/flutter (18969): Another exception was thrown: 'package:flutter/src/widgets/scrollable.dart': Failed assertion: line 534 pos 12: '_drag == null': is not true.
W/HiTouch_PressGestureDetector(18969): Touch pointer move a lot. The moving distance of X is:51.0, limit is:60The moving distance of Y is:85.0, limit is:60
I/flutter (18969): Another exception was thrown: 'package:extended_nested_scroll_view/src/old_extended_nested_scroll_view.dart': Failed assertion: line 725 pos 16: 'ext
ra <= 0.0': is not true.

I got this issue when upgrade flutter to 1.7 stable version. thanks

Compiler message:
file:///E:/Flutter/flutter/.pub-cache/hosted/pub.dartlang.org/extended_nested_scroll_view-0.3.5/lib/src/nested_scroll_view_refresh_indicator.dart:363:24: Error: The argument type 'String' can't be assigned to the parameter type 'DiagnosticsNode'.

  • 'DiagnosticsNode' is from 'package:flutter/src/foundation/diagnostics.dart' ('file:///E:/Flutter/flutter/packages/flutter/lib/src/foundation/diagnostics.dart').
    Try changing the type of the parameter, or casting the argument to 'DiagnosticsNode'.
    context: 'when calling onRefresh',
    ^
    Compiler failed on E:\Flutter_projects\Lari.id.flutter - Copy (2)\lib/main.dart

FAILURE: Build failed with an exception.

NestedScrollView 滚动列表在某些机型上滚动假死

你好,我在使用了 extended_nested_scroll_view 的 pinnedHeaderSliverHeightBuilder 之后,
在某些机型(iphone6,应该跟列表的可视高度有关)上,当列表的的滚动高度在某个范围内,滚动时,列表会发生假死(NestedScrollView 再没有响应)

这是我的项目地址:https://github.com/zZ-wWw/flutter_app
我的Flutter版本:

$ flutter doctor
[✓] Flutter (Channel stable, v1.12.13+hotfix.8, on Mac OS X 10.15.3 19D76, locale zh-Hans-CN)
[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
[✓] Xcode - develop for iOS and macOS (Xcode 11.3.1)
[✓] Android Studio (version 3.6)
[!] IntelliJ IDEA Ultimate Edition (version 2018.3.5)
✗ Flutter plugin not installed; this adds Flutter specific functionality.
✗ Dart plugin not installed; this adds Dart specific functionality.
[✓] VS Code (version 1.42.1)
[✓] Connected device (1 available)

maxContainerExtent在滑动到一定程度之后,始终为固定值?

maxContainerExtent = math.max(
notification.metrics.viewportDimension, this.maxContainerExtent);
maxContainerExtent在滑动到一定程度之后,始终为固定值,
上拉加载如何实现,或者想在外部,body里面通过Controller 操作 _innerController进行jumpTo等操作如何实现,
有什么好的思路吗?

[Feature Request] For outer scroller: Enable "AlwaysScrollableScrollPhysics" (or allow using any custom physics)

Hi! This is a great package already and I am grateful to you for doing all this work. I've seen many issues from you for 2 years solving this problem.

I almost have the desired behavior. If you can modify the package to allow using any custom physics or AlwaysScrollableScrollPhysicsfor outer scroller, my work will be done.

Currently, even though there is a physics parameter for NestedScrollView, changing it doesn't work.

Expected Behavior: (For example the iOS version of the Instagram app --> go to profile screen)

  1. Inner scroller should not bounce (or cannot be over scrolled) on the top edge (leading edge). When scrolling to the top of the page if the inner scroller reaches to minScrollExtent, it should clamp. Currently, I use ClampedScrollPhysics to stop it bounce or be over scrolled. This problem is resolved as you already said.

  2. The outer scroller can be over-scrolled or should bounce on the top edge if there is momentum. Like a pull to refresh mechanism and also I just want it to bounce instead of clamping.

  3. Inner scroller should bounce when reached to the bottom edge. I use my own scroll to load more mechanism by the way.

  4. The scroll friction should be lowered and the scroll detection threshold should be lowered too. This will improve the ease of use. Of course, if custom physics can be applied, I can fine-tune it by myself.

Sample video of the current situation:

Nested Scroll Physics - streamable.com - Sorry, Streamable.com deleted the videos due to prescription

Instagram example:

Instagram Profile Screen Nested Scrolling (Bounces and Can Be Over Scrolled) - Sorry, Streamable.com deleted the videos due to prescription

A Basic Reproducible Code:

import 'package:flutter/material.dart' hide NestedScrollView;
import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart' as extended;


class NestedWithTabs extends StatefulWidget {
  @override
  _NestedWithTabsState createState() => _NestedWithTabsState();
}

class _NestedWithTabsState extends State<NestedWithTabs> with TickerProviderStateMixin {
  TabController tabController;
  static List<String> _tabButtonTextList = ["Dogs", "Cats", "Birds"];
  List<Key> _keyList = [];
  static double _tabButtonHeight = 48;
  static double _headerWidgetHeight = 250;

  @override
  void initState() {
    super.initState();

    tabController = TabController(
      length: _tabButtonTextList.length,
      initialIndex: 0,
      vsync: this,
    );

    for (var i = 0; i < _tabButtonTextList.length; i++) {
      _keyList.add(Key(_tabButtonTextList[i] + i.toString()));
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: extended.NestedScrollView(
        physics: AlwaysScrollableScrollPhysics(), // THIS DOES NOT WORK?
        pinnedHeaderSliverHeightBuilder: () => _tabButtonHeight,
        headerSliverBuilder: (BuildContext c, bool f) {
          final List<Widget> widgets = <Widget>[];
          widgets.add(
            SliverList(
              delegate: SliverChildListDelegate(
                [
                  Container(
                    color: Colors.red,
                    height: _headerWidgetHeight,
                    child: Center(
                      child: Text("Header Widget"),
                    ),
                  ),
                ],
              ),
            ),
          );
          widgets.add(
            SliverPersistentHeader(
              pinned: true,
              floating: false,
              delegate: CommonSliverPersistentHeaderDelegate(
                Container(
                  height: _tabButtonHeight,
                  child: TabBar(
                    controller: tabController,
                    labelColor: Colors.blue,
                    indicatorColor: Colors.black,
                    indicatorSize: TabBarIndicatorSize.label,
                    indicatorWeight: 2.0,
                    isScrollable: false,
                    unselectedLabelColor: Colors.grey,
                    tabs: _tabButtonTextList.asMap().entries.map((entry) {
                      return Tab(text: entry.value);
                    }).toList(),
                  ),
                ),
                _tabButtonHeight,
              ),
            ),
          );

          return widgets;
        },
        innerScrollPositionKeyBuilder: () => _keyList[tabController.index],
        body: TabBarView(
          controller: tabController,
          children: _tabButtonTextList.asMap().entries.map((entry) {
            int _thisIndex = entry.key;
            return InnerScroller(
              tabKey: _keyList[_thisIndex],
              tabIndex: _thisIndex,
              tabName: _tabButtonTextList[_thisIndex],
            );
          }).toList(),
        ),
      ),
    );
  }
}

/* -------------------------------------------------------------------------- */
/*                    CommonSliverPersistentHeaderDelegate                    */
/* -------------------------------------------------------------------------- */

class CommonSliverPersistentHeaderDelegate extends SliverPersistentHeaderDelegate {
  CommonSliverPersistentHeaderDelegate(this.child, this.height);
  final Widget child;
  final double height;

  @override
  double get minExtent => height;

  @override
  double get maxExtent => height;

  @override
  Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
    return child;
  }

  @override
  bool shouldRebuild(CommonSliverPersistentHeaderDelegate oldDelegate) {
    //print('shouldRebuild---------------');
    return oldDelegate != this;
  }
}

/* -------------------------------------------------------------------------- */
/*                                InnerScroller                               */
/* -------------------------------------------------------------------------- */

class InnerScroller extends StatefulWidget {
  final Key tabKey;
  final int tabIndex;
  final String tabName;
  InnerScroller({
    @required this.tabKey,
    @required this.tabIndex,
    @required this.tabName,
  });

  @override
  _InnerScrollerState createState() => _InnerScrollerState();
}

class _InnerScrollerState extends State<InnerScroller> with AutomaticKeepAliveClientMixin {
  static List<Color> _colorList = [Colors.indigoAccent, Colors.lime, Colors.orangeAccent];

  @override
  Widget build(BuildContext context) {
    return extended.NestedScrollViewInnerScrollPositionKeyWidget(
      widget.tabKey,
      CustomScrollView(
        key: PageStorageKey(widget.tabKey),
        physics: ClampingScrollPhysics(),
        slivers: <Widget>[
          SliverGrid(
            delegate: SliverChildBuilderDelegate(
              (_, i) {
                return Container(
                  margin: EdgeInsets.all(4),
                  height: 200,
                  color: _colorList[widget.tabIndex],
                  child: Center(
                    child: Text(widget.tabName + " " + i.toString()),
                  ),
                );
              },
              childCount: 3 * 32,
            ),
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
              crossAxisCount: 3,
            ),
          ),
        ],
      ),
    );
  }

  @override
  bool get wantKeepAlive => true;
}

更新了最新flutter 的sdk后,编译不通过

Flutter 1.7.4-pre.105 • channel master
Dart 2.4.0

error:

Compiler message:
file:///Users/lee/tools/flutter/.pub-cache/hosted/pub.flutter-io.cn/extended_nested_scroll_view-0.3.5/lib/src/nested_scroll_view_refresh_indicator.dart:363:24: Error: The argument type 'String' can't be assigned to the parameter type 'DiagnosticsNode'.

  • 'DiagnosticsNode' is from 'package:flutter/src/foundation/diagnostics.dart' ('file:///Users/lee/tools/flutter/packages/flutter/lib/src/foundation/diagnostics.dart').
    Try changing the type of the parameter, or casting the argument to 'DiagnosticsNode'.
    context: 'when calling onRefresh',
    ^
    Compiler terminated unexpectedly.

这么传参可以通过
context: DiagnosticsNode.message('when calling onRefresh'),

the internal elastic scroll is not clean by extended_nested_scroll_view

While dragging the page to the top, quickly pull up, the page will shake. I guess the internal elastic scroll is not clean by extended_nested_scroll_view. The simulator is good, only the real machine has problems.

import 'dart:io';
import 'package:flutter/material.dart' hide NestedScrollView;
import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primaryColor: Colors.white,
      ),
      home: NewsScreen(),
      debugShowCheckedModeBanner: false,
    );
  }
}

class NewsScreen extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _NewsScreenState();
}

class _NewsScreenState extends State<NewsScreen> with TickerProviderStateMixin {
  final List<String> _tabs = <String>[
    "Featured",
    "Popular",
    "Latest",
  ];
  TabController _tabController;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: _tabs.length, vsync: this);
  }

  @override
  void dispose() {
    _tabController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Material(
      child: Scaffold(
        body: NestedScrollView(
          headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
            return <Widget>[
              SliverOverlapAbsorber(
                handle:
                    NestedScrollView.sliverOverlapAbsorberHandleFor(context),
                sliver: SliverSafeArea(
                  top: false,
                  bottom: Platform.isIOS ? false : true,
                  sliver: SliverAppBar(
                    title: Text('Tab Demo'),
                    floating: true,
                    pinned: true,
                    snap: true,
                    forceElevated: innerBoxIsScrolled,
                    bottom: TabBar(
                      controller: _tabController,
                      tabs:
                          _tabs.map((String name) => Tab(text: name)).toList(),
                    ),
                  ),
                ),
              ),
            ];
          },
          innerScrollPositionKeyBuilder: () {
            return Key('Tab${_tabController.index}');
          },
          body: TabBarView(
            controller: _tabController,
            children: _tabs.asMap().entries.map((entry) {
              return TabViewItem(
                tabKey: Key('Tab${entry.key}'),
                tabName: entry.value,
              );
            }).toList(),
          ),
        ),
      ),
    );
  }
}

class TabViewItem extends StatefulWidget {
  final Key tabKey;
  final String tabName;

  const TabViewItem({Key key, this.tabKey, this.tabName}) : super(key: key);

  @override
  _TabViewItemState createState() => _TabViewItemState();
}

class _TabViewItemState extends State<TabViewItem>
    with AutomaticKeepAliveClientMixin {
  @override
  Widget build(BuildContext context) {
    super.build(context);
    return SafeArea(
      top: false,
      bottom: false,
      child: Builder(
        builder: (BuildContext context) {
          return NotificationListener<ScrollNotification>(
            onNotification: (scrollNotification) {
              return true;
            },
            child: NestedScrollViewInnerScrollPositionKeyWidget(
              widget.tabKey,
              CustomScrollView(
                slivers: <Widget>[
                  SliverOverlapInjector(
                    handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
                        context),
                  ),
                  SliverPadding(
                    padding: const EdgeInsets.all(8.0),
                    sliver: SliverList(
                      delegate: SliverChildBuilderDelegate(
                        (BuildContext context, int index) {
                          return Column(
                            children: <Widget>[
                              Container(
                                height: 150,
                                width: double.infinity,
                                color: Colors.blueGrey,
                                child: Column(
                                  mainAxisAlignment: MainAxisAlignment.center,
                                  children: <Widget>[
                                    Text('${widget.tabName} $index')
                                  ],
                                ),
                              ),
                              SizedBox(
                                height: 8,
                              )
                            ],
                          );
                        },
                        childCount: 30,
                      ),
                    ),
                  ),
                ],
              ),
            ),
          );
        },
      ),
    );
  }

  @override
  bool get wantKeepAlive => true;
}

The method 'toDouble' was called on null.

Hi!

First of all thank you for this awesome lib.
I have an error, however it's not consequent. I have a PageView with several pages. All of the pages contains a NestedScrollView. The relevant error is:

The following NoSuchMethodError was thrown building Builder(dirty):
The method 'toDouble' was called on null.
Receiver: null
Tried calling: toDouble()

The relevant error-causing widget was: 
  NestedScrollView-[LabeledGlobalKey<NestedScrollViewState>#c931d] file:///F:/demo/lib/module_list.dart:114:35
When the exception was thrown, this was the stack: 
#0      Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
#1      double.> (dart:core-patch/double.dart:96:31)
#2      _NestedScrollCoordinator.hasScrolledBody (package:extended_nested_scroll_view/src/old_extended_nested_scroll_view.dart:548:27)
#3      NestedScrollViewState.build.<anonymous closure> (package:extended_nested_scroll_view/src/old_extended_nested_scroll_view.dart:366:47)
#4      Builder.build (package:flutter/src/widgets/basic.dart:6757:41)

It usually occurs when I swipe in the PageView really fast.

Do you have an idea what's going on?
Thank you.

1.SliverPadding 组件会叠加在pinned上 2.SliverPersistentHeader overlapsContent 和 shrinkOffset 失效

import 'package:flutter/material.dart' hide NestedScrollView;
import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart';

void main() {
runApp(MyApp());
}

class MyApp extends StatelessWidget {
@OverRide
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}

class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);

final String title;
@OverRide
_MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State
with SingleTickerProviderStateMixin {
TabController tabController;
@OverRide
void initState() {
super.initState();
this.tabController = TabController(length: 4, vsync: this);
}

Future _onRefresh() {}

//tab
Widget _tabListWidget(bool ceiling) {
return Container(
padding: EdgeInsets.symmetric(horizontal: 15),
color: ceiling ? Colors.white : Colors.transparent,
height: 50,
child: TabBar(
labelColor: Colors.black,
controller: this.tabController,
indicatorWeight: 3.5,
indicatorSize: TabBarIndicatorSize.label,
indicatorColor: Colors.red,
labelStyle: TextStyle(fontSize: 17, fontWeight: FontWeight.bold),
unselectedLabelStyle: TextStyle(
fontSize: 15,
),
tabs: [
Tab(text: '精选产品'),
Tab(text: '吃货联盟'),
Tab(text: '电脑办公'),
Tab(text: '生活家电'),
],
),
);
}

//tabview
Widget _tabViewWidget() {
return Container(
child: ListView.builder(
itemBuilder: (BuildContext context, int index) {
return Container(
height: 30,
child: Text('$index'),
);
},
itemCount: 100,
),
);
}

@OverRide
Widget build(BuildContext context) {
final double statusBarHeight = MediaQuery.of(context).padding.top;
return Scaffold(
body: NestedScrollViewRefreshIndicator(
onRefresh: _onRefresh,
child: NestedScrollView(
headerSliverBuilder: (context, ceiling) {
return [
//搜索框
SliverAppBar(
pinned: true,
elevation: 0,
title: Text('搜索栏'),
),

              //间隔
              SliverPadding(
                padding: EdgeInsets.all(20),
              ),

              SliverToBoxAdapter(
                child: Container(
                  height: 1500,
                  color: Colors.red,
                ),
              ),

              //间隔
              SliverPadding(
                padding: EdgeInsets.all(20),
              ),

              // tab头部
              SliverPersistentHeader(
                pinned: true,
                delegate: StickyTabBarDelegate(
                  child: this._tabListWidget(false),
                  ceiling: this._tabListWidget(true),
                ),
              ),
            ];
          },
          pinnedHeaderSliverHeightBuilder: () {
            return statusBarHeight + kToolbarHeight + 50;
          },
          innerScrollPositionKeyBuilder: () {
            var index = "Tab";
            index += tabController.index.toString();
            return Key(index);
          },
          body: TabBarView(
            controller: this.tabController,
            children: <Widget>[
              NestedScrollViewInnerScrollPositionKeyWidget(
                  Key("Tab0"), _tabViewWidget()),
              NestedScrollViewInnerScrollPositionKeyWidget(
                  Key("Tab1"), _tabViewWidget()),
              NestedScrollViewInnerScrollPositionKeyWidget(
                  Key("Tab2"), _tabViewWidget()),
              NestedScrollViewInnerScrollPositionKeyWidget(
                  Key("Tab3"), _tabViewWidget()),
            ],
          ))),
);

}
}

class StickyTabBarDelegate extends SliverPersistentHeaderDelegate {
final child;
final ceiling;

StickyTabBarDelegate({@required this.child, @required this.ceiling});

@OverRide
Widget build(
BuildContext context, double shrinkOffset, bool overlapsContent) {
return overlapsContent ? this.ceiling : this.child;
}

@OverRide
double get maxExtent => 50;

@OverRide
double get minExtent => 50;

@OverRide
bool shouldRebuild(SliverPersistentHeaderDelegate oldDelegate) {
return true;
}
}

完全没看懂是咋操作的

项目里也是碰到了这种nestedScroll + tabbar + tabbarView
准备直接copy过来了...
有什么新的解决办法吗? 我仔细读了一下好像是监听了个什么通知...

The non-abstract class '_NestedScrollPosition' is missing implementations for these members: - ScrollPosition.pointerScroll

On Flutter 2.0, I get this error when trying to build the app.
I use version 2.0.1 of this package - the latest version.

../../../../flutter/.pub-cache/hosted/pub.dartlang.org/extended_nested_scroll_view-2.0.1/lib/src/old_extended_nested_scroll_view.dart:1229:7: Error: The non-abstract class '_NestedScrollPosition' is missing implementations for these members:
 - ScrollPosition.pointerScroll                                         
Try to either                                                           
 - provide an implementation,                                           
 - inherit an implementation from a superclass or mixin,                
 - mark the class as abstract, or                                       
 - provide a 'noSuchMethod' implementation.                             
                                                                        
class _NestedScrollPosition extends ScrollPosition                      
      ^^^^^^^^^^^^^^^^^^^^^                                             
../../../../flutter/packages/flutter/lib/src/widgets/scroll_position.dart:777:8: Context: 'ScrollPosition.pointerScroll' is defined here.
  void pointerScroll(double delta);           

Please help,
Thanks

似乎并没有解决 issue 2 滚动问题

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin {
  final List<String> _tabs = [
    "AAA",
    "BBB",
    "CCC",
    "DDD",
    "EEE",
    "FFF",
  ];

  TabController tcl;

  @override
  void initState() {
    super.initState();
    tcl = TabController(length: _tabs.length, vsync: this);
  }

  @override
  void dispose() {
    tcl.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final double statusBarHeight = MediaQuery.of(context).padding.top;
    final double pinnedHeaderHeight = statusBarHeight + kToolbarHeight;

    return extended.NestedScrollView(
      pinnedHeaderSliverHeightBuilder: () {
        return pinnedHeaderHeight;
      },
      innerScrollPositionKeyBuilder: () => Key('${_tabs[tcl.index]}'),
        headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
          // These are the slivers that show up in the "outer" scroll view.
          return <Widget>[
//            SliverOverlapAbsorber(
              // This widget takes the overlapping behavior of the SliverAppBar,
              // and redirects it to the SliverOverlapInjector below. If it is
              // missing, then it is possible for the nested "inner" scroll view
              // below to end up under the SliverAppBar even when the inner
              // scroll view thinks it has not been scrolled.
              // This is not necessary if the "headerSliverBuilder" only builds
              // widgets that do not overlap the next sliver.
//              handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
//              sliver:
          SliverAppBar(
                title: const Text('Books'), // This is the title in the app bar.
                pinned: true,
                floating: true,
                snap: true,
                // The "forceElevated" property causes the SliverAppBar to show
                // a shadow. The "innerBoxIsScrolled" parameter is true when the
                // inner scroll view is scrolled beyond its "zero" point, i.e.
                // when it appears to be scrolled below the SliverAppBar.
                // Without this, there are cases where the shadow would appear
                // or not appear inappropriately, because the SliverAppBar is
                // not actually aware of the precise position of the inner
                // scroll views.
                forceElevated: innerBoxIsScrolled,
                bottom: TabBar(
                  controller: tcl,
                  isScrollable: true,
                  // These are the widgets to put in each tab in the tab bar.
                  tabs: _tabs.map((String name) => Tab(text: name)).toList(),
                ),
              ),
//            ),
          ];
        },
        body: TabBarView(
          controller: tcl,
          // These are the contents of the tab views, below the tabs.
          children: _tabs.map((String name) {
            return SafeArea(
              top: false,
              bottom: false,
              child: Builder(
                // This Builder is needed to provide a BuildContext that is
                // "inside" the NestedScrollView, so that
                // sliverOverlapAbsorberHandleFor() can find the
                // NestedScrollView.
                builder: (BuildContext context) {
                  return RefreshIndicator(child: CustomScrollView(
                    // The "controller" and "primary" members should be left
                    // unset, so that the NestedScrollView can control this
                    // inner scroll view.
                    // If the "controller" property is set, then this scroll
                    // view will not be associated with the NestedScrollView.
                    // The PageStorageKey should be unique to this ScrollView;
                    // it allows the list to remember its scroll position when
                    // the tab view is not on the screen.
                    key: PageStorageKey<String>(name),
                    slivers: <Widget>[
//                      SliverOverlapInjector(
//                        // This is the flip side of the SliverOverlapAbsorber
//                        // above.
//                        handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
//                      ),
                      SliverPadding(
                        padding: const EdgeInsets.all(0),
                        // In this example, the inner scroll view has
                        // fixed-height list items, hence the use of
                        // SliverFixedExtentList. However, one could use any
                        // sliver widget here, e.g. SliverList or SliverGrid.
                        sliver: TabPage(key: Key(name)),
                      ),
                    ],
                  ), onRefresh: () => Future.delayed(Duration(seconds: 5)));
                },
              ),
            );
          }).toList(),
        ),
      );
  }
}

class TabPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _TabPageState();
  }

  TabPage({Key key}) : super(key: key);
}

class _TabPageState extends State<TabPage> with AutomaticKeepAliveClientMixin {
  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return extended.NestedScrollViewInnerScrollPositionKeyWidget(
        widget.key,
        SliverFixedExtentList(
          // The items in this example are fixed to 48 pixels
          // high. This matches the Material Design spec for
          // ListTile widgets.
          itemExtent: 48.0,
          delegate: SliverChildBuilderDelegate(
            (BuildContext context, int index) {
              // This builder is called for each child.
              // In this example, we just number each list item.
              return Material(
                  child: ListTile(
                title: Text('Item $index'),
              ));
            },
            // The childCount of the SliverChildBuilderDelegate
            // specifies how many children this inner list
            // has. In this example, each tab has a list of
            // exactly 30 items, but this is arbitrary.
            childCount: 30,
          ),
        ));
  }
}

TabbarVIew重载问题

环境

我运行了大佬的demo项目,进入了NestedScrollView页面,进入SecondTabView文件 ,然后在下图25行处print字符串
image
image

现象

滑动TabBarView里的列表时 整个页面会重新build,控制台输出结果如下
image

期望

我自己的项目里 TabBarView内有很多图片 这会导致每次滑动图片都会重绘 体验不是很好,不知大佬是否有方法优化

`
:~ blurfir$ flutter doctor -v
[✓] Flutter (Channel stable, v1.12.13+hotfix.8, on Mac OS X 10.14.5 18F132,
locale zh-Hans-CN)
• Flutter version 1.12.13+hotfix.8 at /Users/blurfir/flutter
• Framework revision 0b8abb4724 (3 months ago), 2020-02-11 11:44:36 -0800
• Engine revision e1e6ced81d
• Dart version 2.7.0

[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.2)
• Android SDK at /Users/blurfir/Library/Android/sdk
• Android NDK location not configured (optional; useful for native profiling
support)
• Platform android-29, build-tools 29.0.2
• ANDROID_HOME = /Users/blurfir/Library/Android/sdk
• Java binary at: /Applications/Android
Studio.app/Contents/jre/jdk/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build
1.8.0_202-release-1483-b49-5587405)
• All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 11.3.1)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Xcode 11.3.1, Build version 11C504
• CocoaPods version 1.8.4

[✓] Android Studio (version 3.5)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin version 42.1.1
• Dart plugin version 191.8593
• Java version OpenJDK Runtime Environment (build
1.8.0_202-release-1483-b49-5587405)

[✓] VS Code (version 1.44.1)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.9.1

[✓] Connected device (1 available)
• iPhone 8 • D026A059-3954-4013-87EC-43659B1C69B9 • ios •
com.apple.CoreSimulator.SimRuntime.iOS-13-3 (simulator)
`

Reverse CustomScrollview inside a NestedScrollView does scroll in the wrong direction

Steps to Reproduce

I did create a NestedScrollView with a SliverAppBar and a Tabview that consists of CustomScrollViews which are set to reverse = true. Everything works and looks as expected, except that the CustomScorllViews scroll in the opposite direction of the drag/swipe. The SliverAppBar is scrolling correctly. In other words the SliverAppBar and the CustomScrollViews do scroll in different directions.

Please consider this code snippet to reproduce the issue:

    return Scaffold(
      body: NestedScrollView(
        reverse: false,
        headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
          return <Widget>[
            SliverOverlapAbsorber(
              handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
              child: SliverAppBar(
                pinned: true,
                expandedHeight: 80,
                forceElevated: innerBoxIsScrolled,
                flexibleSpace: LayoutBuilder(builder:
                    (BuildContext context, BoxConstraints constraints) {
                  return FlexibleSpaceBar(
                    title: Text("Test"),
                  );
                }),
              ),
            ),
          ];
        },
        body: DefaultTabController(
          length: 3,
          child: TabBarView(
            children: [1, 2, 3].map((int index) {
              return SafeArea(
                top: false,
                bottom: false,
                child: Builder(
                  builder: (BuildContext context) {
                    return CustomScrollView(
                      reverse: true,
                      key: PageStorageKey<String>(index.toString()),
                      slivers: <Widget>[
                        SliverOverlapInjector(
                          handle:
                              NestedScrollView.sliverOverlapAbsorberHandleFor(
                                  context),
                        ),
                        SliverList(
                          delegate: SliverChildBuilderDelegate(
                            (BuildContext context, int index) {
                              return ListTile(title: Text("Item $index"));
                            },
                          ),
                        ),
                      ],
                    );
                  },
                ),
              );
            }).toList(),
          ),
        ),
      ),
    );

This bug also exists in the original NestedScrollView, but since google seems to ignore those issues i was hoping you could solve this problem in your extension?

Demo中ScrollToTop页面列表和Tabbar直接有一段空白,应该如何去掉?

出现步骤:image
系统信息:
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, v1.9.1+hotfix.4, on Mac OS X 10.15.1 19B88, locale en-CN)

[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
[✓] Xcode - develop for iOS and macOS (Xcode 11.2)
[✓] Android Studio (version 3.5)
[✓] VS Code (version 1.39.2)
[✓] Connected device (1 available)

• No issues found!

版本号:0.3.8
补充说明:使用普通的ListView或者LoadMoreList不会出现问题,自己封装了一个加载更多的组件会出现列表顶部的空白,检查页面没有发现添加了Padding,应该是中间多了一个组件,烦请看看如何解决?

Reversed ListView inside NestedScrollView

Hi,
First of all, thanks for the great lib! It fixes some annoying issues with NestedScrollView.

One issue that it didn't fix though is this one: flutter/flutter#39134

This issue happens when you add a reversed ListView to a NestedScrollView.
Would you have any guesses on how this could be solved? I don't understand the inner workings of the NestedScrollView implementation so I thought someone here might be able to help.

Thanks a lot

Luccas

tabview滚动问题。

当使用AutomaticKeepAliveClientMixin 。现在有tabview1 和 tabview2 。当tabview1的滚动吸顶,当切换到tabview2的时候取消滚动吸顶。但是因为tabview1的状态是被记录了还是属于滚动了一部分状态。这个问题怎么解决?

列表开启切换缓存时的bug

TabBarView开启切换缓存时,tab1上划,切换到tab0下划,然后切换到tab1,tab1列表内容仍为之前滑到的位置

pull to refresh not working on ios

Hi, thanks for the plugin, i tried to implement this plugin on my apps,
its working on Android but not on iOS

Screen Shot 2020-05-28 at 19 07 57

that is how i implement NestedScrollViewRefreshIndicator on my App

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.