1

拥有一个SliverAppBarTabBar一个项目列表会导致滚动控制器抱怨。

我已经通过以下方式实现了它,有一个包含NestedScrollViewa 的SliverAppBar,一个SliverPersistentHeader包含 theTabBar的主体,然后NestedScrollView是包含TabBarViewwith SliverListsinside的主体CustomScrollViews

滚动控制器似乎会导致问题。它说它附加到多个视图。所以我尝试为每个自定义滚动视图添加一个新的滚动控制器,但这会阻止 sliver 应用栏在滚动列表本身时折叠。

除此之外,它也不记得切换标签时的滚动状态......我试过使用AutomaticKeepAliveClientMixin,但这似乎不起作用。关于如何解决滚动问题和滚动控制器状态的任何建议都会受到欢迎?:)

另请注意:我仅在 Flutter Web 上进行测试,而不是在移动设备上进行测试...

我不知道这是我的代码中的错误还是颤振中的错误。

请参阅下面的颤振医生:

Doctor summary (to see all details, run flutter doctor -v):
[√] Flutter (Channel unknown, 2.5.0, on Microsoft Windows [Version 10.0.22000.434], locale en-ZA)
[!] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
    X cmdline-tools component is missing
      Run `path/to/sdkmanager --install "cmdline-tools;latest"`
      See https://developer.android.com/studio/command-line for more details.
    X Android license status unknown.
      Run `flutter doctor --android-licenses` to accept the SDK licenses.
      See https://flutter.dev/docs/get-started/install/windows#android-setup for more details.
[√] Chrome - develop for the web
[√] Android Studio (version 4.0)
[√] Connected device (2 available)

! Doctor found issues in 1 category.

滚动控制器抛出的异常如下:

══╡ EXCEPTION CAUGHT BY ANIMATION LIBRARY ╞═════════════════════════════════════════════════════════
The following assertion was thrown while notifying status listeners for AnimationController:
The provided ScrollController is currently attached to more than one ScrollPosition.
The Scrollbar requires a single ScrollPosition in order to be painted.
When the scrollbar is interactive, the associated Scrollable widgets must have unique
ScrollControllers. The provided ScrollController must be unique to a Scrollable widget.

When the exception was thrown, this was the stack:
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/ddc_runtime/errors.dart 251:49  throw_
packages/flutter/src/widgets/scrollbar.dart 1315:9                                                                         <fn>
packages/flutter/src/widgets/scrollbar.dart 1338:14                                                                        [_debugCheckHasValidScrollPosition]
packages/flutter/src/widgets/scrollbar.dart 1257:14                                                                        [_validateInteractions]
packages/flutter/src/animation/listener_helpers.dart 233:27                                                                notifyStatusListeners
packages/flutter/src/animation/animation_controller.dart 814:7                                                             [_checkStatusChanged]
packages/flutter/src/animation/animation_controller.dart 748:5                                                             [_startSimulation]
packages/flutter/src/animation/animation_controller.dart 611:12                                                            [_animateToInternal]
packages/flutter/src/animation/animation_controller.dart 495:12                                                            reverse
packages/flutter/src/widgets/scrollbar.dart 1412:37                                                                        <fn>
C:/b/s/w/ir/cache/builder/src/out/host_debug/dart-sdk/lib/_internal/js_dev_runtime/private/isolate_helper.dart 48:19       internalCallback

The AnimationController notifying status listeners was:
  AnimationController#25a6e(◀ 1.000)

下面是我的代码:

class MyApp extends StatefulWidget {

  MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() {
    return _MyAppState();
  } 
}

class _MyAppState extends State<MyApp> { // with AutomaticKeepAliveClientMixin

  ScrollController _scrollController = ScrollController();
  bool _isAppBarExpanded = true;

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

    _scrollController.addListener(() {
      _isAppBarExpanded = _scrollController.hasClients && _scrollController.offset < (200 - kToolbarHeight);
      setState(() { });
    });
  }

  @override
  Widget build(BuildContext context) {
    // super.build(context); // AutomaticKeepAlive

    const String title = "Floating App Bar";

    return MaterialApp(
      title: title,
      home: Scaffold(
        body: DefaultTabController(
          length: 2,
          child: NestedScrollView(
            controller: _scrollController,
            headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
              return <Widget> [
                SliverAppBar(
                  backgroundColor: (_isAppBarExpanded) ? Colors.white : Colors.blue,
                  expandedHeight: 200.0,
                  floating: false,
                  pinned: true,
                  flexibleSpace: FlexibleSpaceBar(
                    centerTitle: true,
                    title: Text(
                      "Collapsing Toolbar",
                      style: TextStyle(
                        color: Colors.white,
                        fontSize: 16.0,
                      ),
                    ),
                    background: ClipRRect(
                      borderRadius: BorderRadius.only(
                        bottomLeft: Radius.circular(30.0), 
                        bottomRight: Radius.circular(30.0),
                      ),
                      child: Image.network(
                        "https://images.pexels.com/photos/396547/pexels-photo-396547.jpeg?auto=compress&cs=tinysrgb&h=350",
                        fit: BoxFit.cover,
                      ),
                    ),
                  ),
                ),
                SliverPersistentHeader(
                  delegate: _SliverAppBarDelegate(
                    TabBar(
                      labelColor: Colors.black87,
                      unselectedLabelColor: Colors.grey,
                      tabs: <Widget> [
                        Tab(
                          icon: Icon(Icons.info), 
                          text: "Tab 1",
                        ),

                        Tab(
                          icon: Icon(Icons.lightbulb_outline), 
                          text: "Tab 2",
                        ),
                      ],
                    ),
                  ),
                  pinned: true,
                ),
              ];
            },
            body: TabBarView(
              children: <Widget> [
                CustomScrollView(
                  slivers: <Widget> [
                    SliverList(
                      delegate: SliverChildBuilderDelegate(
                        (BuildContext context, int index) {
                          return Text("Item " + index.toString());
                        },
                        childCount: 200,
                        // addAutomaticKeepAlives: true,
                      ),
                    ),
                  ],
                ),
                CustomScrollView(
                  slivers: <Widget> [
                    SliverList(
                      delegate: SliverChildBuilderDelegate(
                        (BuildContext context, int index) {
                          return Text("Test " + index.toString());
                        },
                        childCount: 100,
                        // addAutomaticKeepAlives: true,
                      ),
                    ),
                  ],
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }

  // for AutomaticKeepAlive
  // @override
  // bool get wantKeepAlive {
  //   return true;
  // }
}

class _SliverAppBarDelegate extends SliverPersistentHeaderDelegate {
  _SliverAppBarDelegate(this._tabBar);

  final TabBar _tabBar;

  @override
  double get minExtent {
    return _tabBar.preferredSize.height + 30;
  }

  @override
  double get maxExtent {
    return _tabBar.preferredSize.height + 30;
  }

  @override
  Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) {
    return Container(
      alignment: Alignment.center,
      color: Theme.of(context).scaffoldBackgroundColor,
      child: Padding(
        padding: EdgeInsets.only(top: 15.0, bottom: 15.0),
        child: _tabBar,
      ),
    );
  }

  @override
  bool shouldRebuild(_SliverAppBarDelegate oldDelegate) {
    return false;
  }
}
4

1 回答 1

2

这个问题可以通过添加另一个来ScrollController解决CustomScrollView

final ScrollController _scrollController2 = ScrollController();
....
 TabBarView(
  children: <Widget>[
    CustomScrollView(
      controller: _scrollController2,

您还可以将另一个添加到 next CustomScrollView

于 2022-01-20T14:17:19.597 回答