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
591 stars 117 forks source link

the internal elastic scroll is not clean by extended_nested_scroll_view #62

Closed bayun2 closed 3 years ago

bayun2 commented 3 years ago

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;
}
bayun2 commented 3 years ago

It's the bug of flutter, has been fixed in this pr https://github.com/flutter/flutter/pull/55069/files, when i update extended_nested_scroll_view version from 1.0.1 to 2.0.1 , I can't reproduce this bug