fluttercandies / extended_nested_scroll_view

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
MIT License
592 stars 119 forks source link

Tab切换滚动高度重置问题 #35

Closed hangaoke1 closed 2 years ago

hangaoke1 commented 4 years ago

请教一个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/dm1@2x.png',
                  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;
}
hangaoke1 commented 4 years ago

测试发现确实在tabView组件缓存的情况下,会出现这种问题

zmtzawqlp commented 4 years ago

1.12.13之后,我发现innerpostion,不管缓存不,都只有一个了。。可怕,我昨天晚上调试了下官方的,我要多花点时间研究下这个变动。。

zmtzawqlp commented 2 years ago

现在的版本还有这个问题吗

zmtzawqlp commented 2 years ago

新的flutter sdk 里面已经修复该问题了