In continuation with question
The solution provided above is good. But hard for me to implement in my project.
Expected results:
- I've created two tabs.
- In each tab I have SingleChildScrollView wrapped with Scrollbar.
- I can not have the primary scrollcontroller in both the tabs, because that throws me exception: "ScrollController attached to multiple scroll views."
- For Tab ONE I use primary scrollcontroller, for Tab TWO I created Scrollcontroller and attached it.
- Widgets in both the tabs should be scrollabale using keyboard and mouse.
Actual results:
- For Tab ONE with primary scrollcontroller I can scroll both by keyboard and dragging scrollbar.
- But for Tab TWO with non primary scrollcontroller, I have to scroll only by dragging scrollbar. This tab doesn't respond to keyboard page up /down keys.
- When keyboard keys are used in Tab TWO actually contents of tab ONE are getting scrolled.
Check code:
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;
}