Flutter NestedScrollView ScrollController当前连接到超过一个ScrollPosition。

huangapple go评论59阅读模式
英文:

Flutter NestedScrollView ScrollController is currently attached to more than one ScrollPosition

问题

我正在构建一个Flutter应用程序,使用SliverAppBar和可滚动的选项卡在Web上,使用NestedScrollView,但是我遇到了一个奇怪的错误:

错误信息:
ScrollBar需要一个单一的ScrollPosition才能绘制。当ScrollBar是交互式的时候,关联的ScrollController必须只附加一个ScrollPosition。提供的ScrollController必须是唯一的,只能用于一个ScrollView小部件。

这个错误发生在我在一个选项卡上滚动然后切换到另一个选项卡,然后在前一个选项卡完全切换之前又返回到前一个选项卡时。

我已经尝试将scrollcontroller添加到CustomScrollView小部件中。我还尝试了

primary: false;

但是这只是使我的SliverAppBar不再与正文一起向上滚动,并且在某些情况下仍然出现相同的错误。

请不要只告诉我将ScrollController()添加到我的CustomScrollView小部件中,这并不是有帮助的。

以下是我出现错误的最小代码示例:

英文:

I am building a Flutter App and on the Web with a SliverAppBar with Tabs that are scrollable using a NestedScrollView and I am getting this weird error:

The Scrollbar requires a single ScrollPosition in order to be painted.
When the scrollbar is interactive, the associated ScrollController must only have one ScrollPosition
attached. The provided ScrollController must be unique to one ScrollView widget.

The error occurs when I scroll on one tab and then move to another tab, then move back to the previous tab before it has fully changed tabs.

I have tried adding a scrollcontroller to the CustomScrollView widgets. I have also tried

primary: false;

However, this just makes it so my SliverAppBar no longer scrolls up with the body and in some cases still has the same error.

PLEASE DO NOT JUST TELL ME TO ADD SCROLLCONTROLLER() TO MY CUSTOMSCROLLVIEW WIDGETS, THIS IS NOT HELPFUL.

Here is my minimal code with the error happening:

import 'package:flutter/material.dart';

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  int _selectedIndex = 0;

  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  static const TextStyle optionStyle =
      TextStyle(fontSize: 30, fontWeight: FontWeight.bold);

  static const List<Widget> _widgetOptions = <Widget>[
    Text(
      'Index 0: Home',
      style: optionStyle,
    ),
    Text(
      'Index 1: Business',
      style: optionStyle,
    ),
    Text(
      'Index 2: School',
      style: optionStyle,
    ),
  ];

  SliverAppBar showSliverAppBar(BuildContext context, String screenTitle) {
    final screenSize = MediaQuery.of(context).size;

    return SliverAppBar(
      elevation: 15,
      backgroundColor: Theme.of(context).colorScheme.primary,
      floating: true,
      pinned: true,
      snap: false,
      centerTitle: true,
      title: Center(
        child: Text(
          screenTitle,
          textAlign: TextAlign.center,
        ),
      ),
      actions: [
        Padding(
          padding: EdgeInsets.only(
            right: screenSize.width * 0.01,
          ),
          child: IconButton(
            onPressed: () {},
            icon: const Icon(
              Icons.person,
            ),
          ),
        ),
      ],
      bottom: const TabBar(
        tabs: [
          Tab(
            icon: Icon(Icons.home),
            text: 'Home',
          ),
          Tab(
            icon: Icon(Icons.calendar_month_outlined),
            text: 'Calendar',
          ),
          Tab(
            icon: Icon(Icons.question_mark),
            text: 'About Us',
          ),
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      drawer: const Drawer(
        child: Column(
          children: <Widget>[
            DrawerHeader(
              curve: SawTooth(12),
              child: Text('I am Drawer'),
            ),
          ],
        ),
      ),
      body: DefaultTabController(
        length: 3,
        child: NestedScrollView(
          headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
            return [
              showSliverAppBar(context, 'Nested Scroll View Error'),
            ];
          },
          body: TabBarView(
            children: [
              CustomScrollView(
                slivers: [
                  SliverList(
                    delegate: SliverChildListDelegate(
                      [
                        Container(
                          height: 600,
                          color: Theme.of(context).colorScheme.secondary,
                          child: const Center(
                            child: Text(
                              'Calendar Tab',
                              style: TextStyle(fontSize: 40),
                            ),
                          ),
                        ),
                        Container(
                          height: 1500,
                          color: Colors.green,
                          child: Center(
                            child: _widgetOptions.elementAt(_selectedIndex),
                          ),
                        ),
                      ],
                    ),
                  ),
                ],
              ),
              CustomScrollView(
                slivers: [
                  SliverList(
                    delegate: SliverChildListDelegate(
                      [
                        Container(
                          height: 600,
                          color: Colors.blue[200],
                          child: const Center(
                            child: Text('Calendar Tab',
                                style: TextStyle(fontSize: 40)),
                          ),
                        ),
                        Container(
                          height: 1200,
                          color: Colors.pink,
                          child: Center(
                            child: _widgetOptions.elementAt(_selectedIndex),
                          ),
                        ),
                      ],
                    ),
                  ),
                ],
              ),
              CustomScrollView(
                slivers: [
                  SliverList(
                    delegate: SliverChildListDelegate(
                      [
                        Container(
                          height: 600,
                          color: Colors.blue[200],
                          child: const Center(
                            child: Text('About Us Tab',
                                style: TextStyle(fontSize: 40)),
                          ),
                        ),
                        Container(
                          height: 1200,
                          color: Colors.pink,
                          child: Center(
                            child: _widgetOptions.elementAt(_selectedIndex),
                          ),
                        ),
                      ],
                    ),
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
      bottomNavigationBar: BottomNavigationBar(
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: 'Home',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.business),
            label: 'Business',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.school),
            label: 'School',
          ),
        ],
        currentIndex: _selectedIndex,
        selectedItemColor: Colors.amber[800],
        onTap: _onItemTapped,
      ),
    );
  }
}

答案1

得分: 1

我发现问题了。原来是一个带有滚动条的tabView引起了问题。

在桌面上,滚动条会自动添加,包括在Chrome上。我只在桌面上遇到了这个问题。来源:https://docs.flutter.dev/release/breaking-changes/default-desktop-scrollbars

看起来与这个问题有关:https://github.com/flutter/flutter/pull/78588

为了解决这个问题,我需要禁用应用程序中的滚动条。所以我进入了我的main.dart,在MaterialApp里面添加了scrollBehavior: ScrollConfiguration.of(context).copyWith(scrollbars: false)。这个简单的改变禁用了滚动条并解决了问题。我还发现,如果我不想在整个应用程序中禁用滚动条,我可以进入单独的CustomScrollView小部件,添加scrollBehavior: ScrollConfiguration.of(context).copyWith(scrollbars: false),也可以解决错误。

修复后的代码:

import 'package:flutter/material.dart';

class HomePage extends StatefulWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  int _selectedIndex = 0;

  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  static const TextStyle optionStyle =
      TextStyle(fontSize: 30, fontWeight: FontWeight.bold);

  static const List<Widget> _widgetOptions = <Widget>[
    Text(
      'Index 0: Home',
      style: optionStyle,
    ),
    Text(
      'Index 1: Business',
      style: optionStyle,
    ),
    Text(
      'Index 2: School',
      style: optionStyle,
    ),
  ];

  SliverAppBar showSliverAppBar(BuildContext context, String screenTitle) {
    final screenSize = MediaQuery.of(context).size;

    return SliverAppBar(
      elevation: 15,
      backgroundColor: Theme.of(context).colorScheme.primary,
      floating: true,
      pinned: true,
      snap: false,
      centerTitle: true,
      title: Center(
        child: Text(
          screenTitle,
          textAlign: TextAlign.center,
        ),
      ),
      actions: [
        Padding(
          padding: EdgeInsets.only(
            right: screenSize.width * 0.01,
          ),
          child: IconButton(
            onPressed: () {},
            icon: const Icon(
              Icons.person,
            ),
          ),
        ),
      ],
      bottom: const TabBar(
        tabs: [
          Tab(
            icon: Icon(Icons.home),
            text: 'Home',
          ),
          Tab(
            icon: Icon(Icons.calendar_month_outlined),
            text: 'Calendar',
          ),
          Tab(
            icon: Icon(Icons.question_mark),
            text: 'About Us',
          ),
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      drawer: const Drawer(
        child: Column(
          children: <Widget>[
            DrawerHeader(
              curve: SawTooth(12),
              child: Text('I am Drawer'),
            ),
          ],
        ),
      ),
      body: DefaultTabController(
        length: 3,
        child: NestedScrollView(
          headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
            return [
              showSliverAppBar(context, 'Nested Scroll View Error'),
            ];
          },
          body: TabBarView(
            children: [
              CustomScrollView(
                scrollBehavior:
                    ScrollConfiguration.of(context).copyWith(scrollbars: false),
                slivers: [
                  SliverList(
                    delegate: SliverChildListDelegate(
                      [
                        Container(
                          height: 600,
                          color: Theme.of(context).colorScheme.secondary,
                          child: const Center(
                            child: Text(
                              'Calendar Tab',
                              style: TextStyle(fontSize: 40),
                            ),
                          ),
                        ),
                        Container(
                          height: 1500,
                          color: Colors.green,
                          child: Center(
                            child: _widgetOptions.elementAt(_selectedIndex),
                          ),
                        ),
                      ],
                    ),
                  ),
                ],
              ),
              CustomScrollView(
                scrollBehavior:
                    ScrollConfiguration.of(context).copyWith(scrollbars: false),
                slivers: [
                  SliverList(
                    delegate: SliverChildListDelegate(
                      [
                        Container(
                          height: 600,
                          color: Colors.blue[200],
                          child: const Center(
                            child: Text('Calendar Tab',
                                style: TextStyle(fontSize: 40)),
                          ),
                        ),
                        Container(
                          height: 1200,
                          color: Colors.pink,
                          child: Center(
                            child: _widgetOptions.elementAt(_selectedIndex),
                          ),
                        ),
                      ],
                    ),
                  ),
                ],
              ),
              CustomScrollView(
                scrollBehavior:
                    ScrollConfiguration.of(context).copyWith(scrollbars: false),
                slivers: [
                  SliverList(
                    delegate: SliverChildListDelegate(
                      [
                        Container(
                          height: 600,
                          color: Colors.blue[200],
                          child: const Center(
                            child: Text('About Us Tab',
                                style: TextStyle(fontSize: 40)),
                          ),
                        ),
                        Container(
                          height: 1200,
                          color: Colors.pink,
                          child: Center(
                            child: _widgetOptions.elementAt(_selectedIndex),
                          ),
                        ),
                      ],
                    ),
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
      bottomNavigationBar: BottomNavigationBar(
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            label: 'Home',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.business),
            label: 'Business',
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.school),
            label: 'School',
          ),
        ],
        currentIndex: _selectedIndex,
        selectedItemColor: Colors.amber[800],
        onTap: _onItemTapped,
      ),
    );
  }
}
英文:

I found the issue. It turns out that a tabView with scrollbars causes the issue.

On desktop scrollbars are automatically added, this includes on Chrome. I was only experiencing this issue on desktop. source: https://docs.flutter.dev/release/breaking-changes/default-desktop-scrollbars

It seems to be related to this: https://github.com/flutter/flutter/pull/78588

To fix this issue I needed to make it so scrollBars were turned off in my application. So I went to my main.dart and inside of MaterialApp I added scrollBehavior: ScrollConfiguration.of(context).copyWith(scrollbars: false). This simple change disabled scrollbars and fixed the issue. I have also found that if I do not want to disable scroll bars in my entire app, I can go into the individual CustomScrollView Widgets and add scrollBehavior: ScrollConfiguration.of(context).copyWith(scrollbars: false) and that would fix the error also.

Fixed code:

import &#39;package:flutter/material.dart&#39;;
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State&lt;HomePage&gt; createState() =&gt; _HomePageState();
}
class _HomePageState extends State&lt;HomePage&gt; {
int _selectedIndex = 0;
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
static const List&lt;Widget&gt; _widgetOptions = &lt;Widget&gt;[
Text(
&#39;Index 0: Home&#39;,
style: optionStyle,
),
Text(
&#39;Index 1: Business&#39;,
style: optionStyle,
),
Text(
&#39;Index 2: School&#39;,
style: optionStyle,
),
];
SliverAppBar showSliverAppBar(BuildContext context, String screenTitle) {
final screenSize = MediaQuery.of(context).size;
return SliverAppBar(
elevation: 15,
backgroundColor: Theme.of(context).colorScheme.primary,
floating: true,
pinned: true,
snap: false,
centerTitle: true,
title: Center(
child: Text(
screenTitle,
textAlign: TextAlign.center,
),
),
actions: [
Padding(
padding: EdgeInsets.only(
right: screenSize.width * 0.01,
),
child: IconButton(
onPressed: () {},
icon: const Icon(
Icons.person,
),
),
),
],
bottom: const TabBar(
tabs: [
Tab(
icon: Icon(Icons.home),
text: &#39;Home&#39;,
),
Tab(
icon: Icon(Icons.calendar_month_outlined),
text: &#39;Calendar&#39;,
),
Tab(
icon: Icon(Icons.question_mark),
text: &#39;About Us&#39;,
),
],
),
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
drawer: const Drawer(
child: Column(
children: &lt;Widget&gt;[
DrawerHeader(
curve: SawTooth(12),
child: Text(&#39;I am Drawer&#39;),
),
],
),
),
body: DefaultTabController(
length: 3,
child: NestedScrollView(
headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
return [
showSliverAppBar(context, &#39;Nested Scroll View Error&#39;),
];
},
body: TabBarView(
children: [
CustomScrollView(
scrollBehavior:
ScrollConfiguration.of(context).copyWith(scrollbars: false),
slivers: [
SliverList(
delegate: SliverChildListDelegate(
[
Container(
height: 600,
color: Theme.of(context).colorScheme.secondary,
child: const Center(
child: Text(
&#39;Calendar Tab&#39;,
style: TextStyle(fontSize: 40),
),
),
),
Container(
height: 1500,
color: Colors.green,
child: Center(
child: _widgetOptions.elementAt(_selectedIndex),
),
),
],
),
),
],
),
CustomScrollView(
scrollBehavior:
ScrollConfiguration.of(context).copyWith(scrollbars: false),
slivers: [
SliverList(
delegate: SliverChildListDelegate(
[
Container(
height: 600,
color: Colors.blue[200],
child: const Center(
child: Text(&#39;Calendar Tab&#39;,
style: TextStyle(fontSize: 40)),
),
),
Container(
height: 1200,
color: Colors.pink,
child: Center(
child: _widgetOptions.elementAt(_selectedIndex),
),
),
],
),
),
],
),
CustomScrollView(
scrollBehavior:
ScrollConfiguration.of(context).copyWith(scrollbars: false),
slivers: [
SliverList(
delegate: SliverChildListDelegate(
[
Container(
height: 600,
color: Colors.blue[200],
child: const Center(
child: Text(&#39;About Us Tab&#39;,
style: TextStyle(fontSize: 40)),
),
),
Container(
height: 1200,
color: Colors.pink,
child: Center(
child: _widgetOptions.elementAt(_selectedIndex),
),
),
],
),
),
],
),
],
),
),
),
bottomNavigationBar: BottomNavigationBar(
items: const &lt;BottomNavigationBarItem&gt;[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: &#39;Home&#39;,
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
label: &#39;Business&#39;,
),
BottomNavigationBarItem(
icon: Icon(Icons.school),
label: &#39;School&#39;,
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.amber[800],
onTap: _onItemTapped,
),
);
}
}

huangapple
  • 本文由 发表于 2023年5月18日 12:12:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/76277687.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定