Flutter web tabbar滚动问题与非主滚动控制器
Posted
技术标签:
【中文标题】Flutter web tabbar滚动问题与非主滚动控制器【英文标题】:Flutter web tabbar scroll issue with non primary scrollcontroller 【发布时间】:2021-08-19 16:54:27 【问题描述】:继续question
上面提供的解决方案很好。但我很难在我的项目中实施。
预期结果:
我创建了两个选项卡。 在每个选项卡中,我都有使用滚动条包裹的 SingleChildScrollView。 我不能在两个选项卡中都有主滚动控制器,因为这会引发异常:“滚动控制器附加到多个滚动视图。” 对于 Tab ONE,我使用主滚动控制器,对于 Tab 2,我创建了 Scrollcontroller 并附加了它。 两个选项卡中的小部件都应该可以使用键盘和鼠标滚动。实际结果:
对于带有主滚动控制器的 Tab ONE,我可以通过键盘和拖动滚动条滚动。 但是对于带有非主滚动控制器的 Tab TWO,我只能通过拖动滚动条来滚动。此选项卡不响应键盘向上/向下翻页键。 当在选项卡 2 中使用键盘键时,实际上选项卡 ONE 的内容会滚动。校验码:
import 'package:flutter/material.dart';
void main()
runApp(MyApp());
class MyApp extends StatelessWidget
// This widget is the root of your application.
@override
Widget build(BuildContext context)
return MaterialApp(
home: TabExample(),
);
class TabExample extends StatefulWidget
const TabExample(Key key) : super(key: key);
@override
_TabExampleState createState() => _TabExampleState();
class _TabExampleState extends State<TabExample>
@override
Widget build(BuildContext context)
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
bottom: TabBar(
tabs: [
Tab(icon: Text('Tab ONE')),
Tab(icon: Text('Tab TWO')),
],
),
title: Text('Tabs Demo'),
),
body: TabBarView(
children: [
WidgetC(),
WidgetD(),
],
),
),
);
class WidgetC extends StatefulWidget
const WidgetC(Key key) : super(key: key);
@override
_WidgetCState createState() => _WidgetCState();
class _WidgetCState extends State<WidgetC>
with AutomaticKeepAliveClientMixin<WidgetC>
List<Widget> children;
@override
void initState()
children = [];
for (int i = 0; i < 20; i++)
children.add(
Padding(
padding: EdgeInsets.symmetric(vertical: 16),
child: Container(
height: 100,
width: double.infinity,
color: Colors.blue,
child: Center(child: Text('$i')),
),
),
);
super.initState();
@override
Widget build(BuildContext context)
super.build(context);
return Scrollbar(
key: PageStorageKey('WidgetC'),
isAlwaysShown: true,
showTrackOnHover: true,
child: SingleChildScrollView(
child: Column(
children: children,
),
),
);
@override
bool get wantKeepAlive => true;
class WidgetD extends StatefulWidget
const WidgetD(Key key) : super(key: key);
@override
_WidgetDState createState() => _WidgetDState();
class _WidgetDState extends State<WidgetD>
with AutomaticKeepAliveClientMixin<WidgetD>
List<Widget> children;
ScrollController _scrollController;
@override
void initState()
_scrollController = ScrollController();
children = [];
for (int i = 0; i < 20; i++)
children.add(
Padding(
padding: EdgeInsets.symmetric(vertical: 16),
child: Container(
height: 100,
width: double.infinity,
color: Colors.green,
child: Center(child: Text('$i')),
),
),
);
super.initState();
@override
void dispose()
_scrollController.dispose();
super.dispose();
@override
Widget build(BuildContext context)
super.build(context);
return Scrollbar(
key: PageStorageKey('WidgetD'),
isAlwaysShown: true,
showTrackOnHover: true,
controller: _scrollController,
child: SingleChildScrollView(
controller: _scrollController,
child: Column(
children: children,
),
),
);
@override
bool get wantKeepAlive => true;
【问题讨论】:
【参考方案1】:这已被接受为颤振中的错误。 请在此处关注进度:https://github.com/flutter/flutter/issues/83711
注意其他面临相同问题的开发人员。 为了克服上述问题,我改变了我的设计布局。我使用的是 Navigationrail 小部件,而不是标签栏视图。这解决了我的问题。 NavigationRail 小部件允许我将主滚动控制器附加到多个小部件而不给我例外:“滚动控制器附加到多个滚动视图。” 示例代码。
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
/// This is the main application widget.
class MyApp extends StatelessWidget
const MyApp(Key key) : super(key: key);
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context)
return const MaterialApp(
title: _title,
home: MyStatefulWidget(),
);
/// This is the stateful widget that the main application instantiates.
class MyStatefulWidget extends StatefulWidget
const MyStatefulWidget(Key key) : super(key: key);
@override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
/// This is the private State class that goes with MyStatefulWidget.
class _MyStatefulWidgetState extends State<MyStatefulWidget>
int _selectedIndex = 0;
WidgetC _widgetC = WidgetC();
WidgetD _widgetD = WidgetD();
@override
Widget build(BuildContext context)
return Scaffold(
appBar: AppBar(title: Text('NavigationRail Demo'), centerTitle: true),
body: Row(
children: <Widget>[
NavigationRail(
elevation: 8.0,
selectedIndex: _selectedIndex,
onDestinationSelected: (int index)
setState(()
_selectedIndex = index;
);
,
labelType: NavigationRailLabelType.all,
groupAlignment: 0.0,
destinations: const <NavigationRailDestination>[
NavigationRailDestination(
icon: Icon(Icons.favorite_border),
selectedIcon: Icon(Icons.favorite),
label: Text('Tab ONE'),
),
NavigationRailDestination(
icon: Icon(Icons.bookmark_border),
selectedIcon: Icon(Icons.book),
label: Text('Tab TWO'),
),
],
),
const VerticalDivider(thickness: 1, width: 1),
// This is the main content.
Expanded(
child: _getPageAtIndex(_selectedIndex),
)
],
),
);
Widget _getPageAtIndex(int index)
switch (index)
case 0:
return _widgetC;
case 1:
return _widgetD;
return Container();
class WidgetC extends StatefulWidget
const WidgetC(Key key) : super(key: key);
@override
_WidgetCState createState() => _WidgetCState();
class _WidgetCState extends State<WidgetC>
with AutomaticKeepAliveClientMixin<WidgetC>
List<Widget> children;
@override
void initState()
children = [];
for (int i = 0; i < 20; i++)
children.add(
Padding(
padding: EdgeInsets.symmetric(vertical: 16),
child: Container(
height: 100,
width: double.infinity,
color: Colors.primaries[Random().nextInt(Colors.primaries.length)],
child: Center(child: Text('$i')),
),
),
);
super.initState();
@override
Widget build(BuildContext context)
super.build(context);
return Scrollbar(
key: PageStorageKey('WidgetC'),
isAlwaysShown: true,
showTrackOnHover: true,
child: SingleChildScrollView(
child: Column(
children: children,
),
),
);
@override
bool get wantKeepAlive => true;
class WidgetD extends StatefulWidget
const WidgetD(Key key) : super(key: key);
@override
_WidgetDState createState() => _WidgetDState();
class _WidgetDState extends State<WidgetD>
with AutomaticKeepAliveClientMixin<WidgetD>
List<Widget> children;
// ScrollController _scrollController;
@override
void initState()
// _scrollController = ScrollController();
children = [];
for (int i = 0; i < 20; i++)
children.add(
Padding(
padding: EdgeInsets.symmetric(vertical: 16),
child: Container(
height: 100,
width: double.infinity,
color: Colors.primaries[Random().nextInt(Colors.primaries.length)],
child: Center(child: Text('$i')),
),
),
);
super.initState();
@override
void dispose()
// _scrollController.dispose();
super.dispose();
@override
Widget build(BuildContext context)
super.build(context);
return Scrollbar(
key: PageStorageKey('WidgetD'),
isAlwaysShown: true,
showTrackOnHover: true,
// controller: _scrollController,
child: SingleChildScrollView(
// controller: _scrollController,
child: Column(
children: children,
),
),
);
@override
bool get wantKeepAlive => true;
【讨论】:
以上是关于Flutter web tabbar滚动问题与非主滚动控制器的主要内容,如果未能解决你的问题,请参考以下文章