Stateless widgets are being called multiple times - flutter

I have come across a strange issue. While implementing a functionality, I noticed that all of my widgets functions are called continuously, resulting in high CPU consumption. To prevent this, I changed all my widgets functions to stateless widgets but unfortunately, the problem still persists. Can anyone guide me as to why this is happening or where I am going wrong?
class BearbeitungWidget extends StatelessWidget {
const BearbeitungWidget({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Consumer<EAProvider>(
builder: (context, v, child) => Container(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Visibility(
visible: v.expandBearWidget,
child: SizedBox(
child: Row(
children: [
SizedBox(
child: Column(
children: const [
SizedBox(child: Text('Vorgang')),
SizedBox(child: Text('Maßnahme')),
],
),
),
// this is called multiple times
_BearbeitungItemWidget(
itemText: 'Technische Prüfung (E)',
gridLength: 11,
backWidgetColor: const Color.fromRGBO(250, 80, 80, 1),
frontWidgetSize: 0.01,
includeIcons: true),
],
),
))
],
),
),
);
}
}
class _BearbeitungItemWidget extends StatelessWidget {
String itemText;
int gridLength;
Color backWidgetColor;
double frontWidgetSize;
bool includeIcons = false;
_BearbeitungItemWidget(
{Key? key,
required this.itemText,
required this.gridLength,
required this.backWidgetColor,
required this.frontWidgetSize,
this.includeIcons = false})
: super(key: key);
#override
Widget build(BuildContext context) {
print('_BearbeitungItemWidget CALLED');
return SizedBox(
child: Column(
children: [
Container(
child: const Text('Maßnahme'),
),
SizedBox(
// this is called multiple times
child: _StackedItemWidget(
backWidgetColor: backWidgetColor,
frontWidgetSize: frontWidgetSize,
includeIcons: includeIcons),
),
// this is called multiple times
_NumberGridWidget(length: gridLength),
],
),
);
}
}
class _NumberGridWidget extends StatelessWidget {
int length;
_NumberGridWidget({Key? key, required this.length}) : super(key: key);
#override
Widget build(BuildContext context) {
print('_NumberGridWidget CALLED');
return Container(
child: Wrap(
children: [
for (var i = 0; i < length; i++)
// this is called multiple times
_GridItemWidget(
text: i,
)
],
),
);
}
}
class _GridItemWidget extends StatelessWidget {
int text;
_GridItemWidget({Key? key, required this.text}) : super(key: key);
#override
Widget build(BuildContext context) {
print('_GridItemWidget CALLED');
return Container(
child: const Text('Maßnahme'),
);
}
}
class _StackedItemWidget extends StatelessWidget {
Color backWidgetColor;
double frontWidgetSize;
bool includeIcons = false;
_StackedItemWidget(
{Key? key,
required this.backWidgetColor,
required this.frontWidgetSize,
this.includeIcons = false})
: super(key: key);
#override
Widget build(BuildContext context) {
print('_StackedItemWidget CALLED');
return Stack(
children: [
// this is called multiple times
_StackedChildItemWidget(
textColor: backWidgetColor,
width: MediaQuery.of(context).size.width * 0.10,
includeIcons: includeIcons),
],
);
}
}
class _StackedChildItemWidget extends StatelessWidget {
Color? textColor;
double? width;
bool includeIcons = false;
_StackedChildItemWidget(
{Key? key, this.textColor, this.width, this.includeIcons = false})
: super(key: key);
#override
Widget build(BuildContext context) {
print('_StackedChildItemWidget CALLED');
return Container(
child: Center(
child: const Text('Maßnahme'),
),
);
}
}

Related

the "inspector" screen is not available for this applacation

class _BottomNavigationBar extends StatelessWidget {
const _BottomNavigationBar({
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return SafeArea(
top: false,
bottom: true,
left: true,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
_BottomNavigationBar(),
_BottomNavigationBar(),
_BottomNavigationBar(),
_BottomNavigationBar(),
],
),
);
}
}
class _NavigationBarItem extends StatelessWidget {
const _NavigationBarItem({super.key});
#override
Widget build(BuildContext context) {
return SafeArea(child: Text('item'));
}
i am meeting this mistake in this window
i did a lot ways but they didnot work they didnt work

Flutter: How to change the state from inside a child widget of AnimatedSwitcher

I have created a screen in flutter that shows a question and displays an array of possible answers as buttons. The questions and answers are inside an AnimatedSwitcher widget, so once an answer button is clicked, the next question and answers should be displayed. Unfortunately, the AnimatedSwitcher widget only works when the button is outside its child widget. This is not the behaviour is want, since I want the answer and buttons to both be part of the animation.
Is there a way to do this or possibly a better widget to use? I'd be thankful for your help!
import 'package:flutter/material.dart';
int index = 0;
final widgets = [
QuestionWidget(
question:
Question("What is your favorite color?", ["red", "blue", "green"]),
key: const Key('1')),
QuestionWidget(
question: Question("How do you do today?", ["great", "not so well"]),
key: const Key('2')),
QuestionWidget(
question: Question("Do you like Flutter", ["yes", "no"]),
key: const Key('3')),
];
class Test extends StatefulWidget {
const Test({Key? key}) : super(key: key);
#override
State<Test> createState() => _TestState();
}
class _TestState extends State<Test> {
#override
void initState() {
super.initState();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
var size = MediaQuery.of(context).size;
return Scaffold(
body: Center(
child: SizedBox(
width: size.width * 0.7,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
AnimatedSwitcher(
duration: const Duration(milliseconds: 400),
transitionBuilder: (child, animation) =>
SlideTransition(
position: Tween<Offset>(
begin: const Offset(0.0, -1.0),
end: const Offset(0.0, 0.0))
.animate(animation),
child: FadeTransition(
opacity: animation, child: child)),
child: widgets[index]),
],
))));
}
}
class QuestionWidget extends StatefulWidget {
final Question question;
const QuestionWidget({
required this.question,
Key? key,
}) : super(key: key);
#override
State<QuestionWidget> createState() => _QuestionWidgetState();
}
class _QuestionWidgetState extends State<QuestionWidget> {
#override
Widget build(BuildContext context) {
return Column(children: [
Text(
widget.question.questionText,
style: const TextStyle(
fontSize: 25,
),
),
Wrap(
direction: Axis.horizontal,
alignment: WrapAlignment.center,
spacing: 5.0,
children: [
for (var i in widget.question.answers)
ElevatedButton(
child: Text(i.toString()),
onPressed: () {
final isLastIndex = index == widgets.length - 1;
setState(() => index = isLastIndex ? 0 : index + 1);
})
],
)
]);
}
}
class Question {
String questionText;
List<String> answers;
Question(this.questionText, this.answers);
}
Storing mutable state in global variables is not a valid approach in Flutter.
One of the main rules in Flutter developement is: state goes down, events go up.
In your case, it seems that the Test widget should be responsible for defining the index of the current question, so you need to make it a part of its State. The Question widget shouldn't care about what to do when the right answer is selected, it should only know how to detect such a event and who to notify about it.
Putting it all together:
Test should store the current question index
Test should select which Question to display at the given moment
Question should notify Test when the right answer is selected
Test should change the current index in response to the event above.
In your case, notifying about the event can be nothing more than just calling a callback provided in a constructor argument.
In code:
class TestState extends State<Test> {
int _index = 0;
#override
Widget build(BuildContext context) {
...
QuestionWidget(
key: Key(index.toString()),
question: questions[index],
onCorrectAnswer: () => setState(() => index++)),
),
...
}
}
class QuestionWidget extends StatelessWidget {
final void Function() onCorrectAnswer;
#override
Widget build(BuildContext context) {
...
ElevatedButton(
onPressed: () => onCorrectAnswer(),
),
...
}
}
I highly recommend reading Flutter docs' take on state management
With the help of mfkw1's answer, I came up with this solution. I struggled a little with this which was because I did not see that the QuestionWidget was turned into a StatelessWidget.
import 'package:flutter/material.dart';
class Test extends StatefulWidget {
const Test({Key? key}) : super(key: key);
#override
State<Test> createState() => _TestState();
}
class _TestState extends State<Test> {
int index = 0;
next() {
final isLastIndex = index == 2;
setState(() => index = isLastIndex ? 0 : index + 1);
}
#override
void initState() {
super.initState();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
final widgets = [
QuestionWidget(
question: Question(
"What is your favorite color?", ["red", "blue", "green"]),
key: const Key("1"),
onAnswer: () => next()),
QuestionWidget(
question: Question("How do you do today?", ["great", "not so well"]),
key: const Key("2"),
onAnswer: () => next()),
QuestionWidget(
question: Question("Do you like Flutter?", ["yes", "no"]),
key: const Key("3"),
onAnswer: () => next()),
];
var size = MediaQuery.of(context).size;
return Scaffold(
body: Center(
child: SizedBox(
width: size.width * 0.7,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
AnimatedSwitcher(
duration: const Duration(milliseconds: 400),
transitionBuilder: (child, animation) =>
SlideTransition(
position: Tween<Offset>(
begin: const Offset(0.0, -1.0),
end: const Offset(0.0, 0.0))
.animate(animation),
child: FadeTransition(
opacity: animation, child: child)),
child: widgets[index]),
],
))));
}
}
class QuestionWidget extends StatelessWidget {
final Question question;
final Function() onAnswer;
const QuestionWidget({
required this.question,
required this.onAnswer,
Key? key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Column(children: [
Text(
question.questionText,
style: const TextStyle(
fontSize: 25,
),
),
Wrap(
direction: Axis.horizontal,
alignment: WrapAlignment.center,
spacing: 5.0,
children: [
for (var i in question.answers)
ElevatedButton(
child: Text(i.toString()),
onPressed: () {
onAnswer();
})
],
)
]);
}
}
class Question {
String questionText;
List<String> answers;
Question(this.questionText, this.answers);
}

How to display data in a table?

I need to display the data that comes to me from the server as an array of objects. The number of objects may vary.
For example -
{"RowNumber":1,"WalletName":"Elsom","PayerPhoneNumber":"996555121212","CreatedDate":"2022-06-10T10:52:00","Amount":50.2,"CurrencyCode":"KGS"},
{"RowNumber":2,"WalletName":"O!","PayerPhoneNumber":"996555131313","CreatedDate":"2022-06-09T22:12:00","Amount":122.3,"CurrencyCode":"KGS"},
You need to display them in the form of a table, how to do this - I don’t understand at all, I processed the response from the server. I made a cycle, but how can I display it on the screen with such a code structure? -
class Report extends StatelessWidget {
var ressultat = json.decode(MyApp.resultat)['Transactions']; //here is an array of objects!!!!!
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Center(
child: , //HERE HERE HERE
],
),
);
}
}
And where can I put the loop? -
var ress = json.decode(MyApp.resultat)['Transactions'];
print(ress[5]['Amount']);
for (int i = 0; i <= ress.length; i++) {
print(ress[i]);
}
I had a similar problem when wanting to see what was returning from a databse on the screen and slapped this together. It's by no means pretty but it does the job, just pass in a Map<String, dynamic> and a String title.
class Tabler extends StatelessWidget {
const Tabler({Key? key, required this.dataMap, required this.title})
: super(key: key);
final Map<String, dynamic> dataMap;
final String title;
#override
Widget build(BuildContext context) {
List<Widget> dataColumns = [];
for (var v in dataMap.values) {
dataColumns.add(_TablerBlock(
dataBlock: v,
));
}
return DefaultTextStyle(
style: TextStyle(fontSize: 25, color: Colors.black),
child: Container(
width: 400,
child: Column(children: <Widget>[
Text(dataMap.toString()),
Text(title),
SizedBox(height: 20),
...dataColumns
])));
}
}
class _TablerBlock extends StatelessWidget {
const _TablerBlock({Key? key, required this.dataBlock}) : super(key: key);
final dynamic dataBlock;
#override
Widget build(BuildContext context) {
List<Widget> block = [];
if (dataBlock is Map<String, dynamic>) {
for (var v in dataBlock.entries) {
block.add(_TablerRow(
dataRow: [v.key, v.value],
));
}
}
return Container(
child: Column(children: <Widget>[
...block,
]));
}
}
class _TablerRow extends StatelessWidget {
const _TablerRow({Key? key, required this.dataRow}) : super(key: key);
final List<dynamic> dataRow;
#override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(dataRow[0].toString() + ': '),
Text(dataRow[1].toString()),
],
);
}
}
Use it by calling
Center(
child: Tabler(dataMap: yourMap, title: 'title');
)
Note that it only works for a single Map.

Flutter - How to Extract Widget with onPressed setState inside?

I want to Extract a Widget with onPressed setState inside but I get the Message "Reference to an enclosing class method cannot be extracted."
Is there a way to do that?
I would like to divide my code into different widgets so that it remains clear. Here is simplified an example of the code:
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Calculator(),
);
}
}
class Calculator extends StatefulWidget {
#override
_CalculatorState createState() => _CalculatorState();
}
class _CalculatorState extends State<Calculator> {
var myValue = 0;
void calculate() {
myValue = 12;
}
#override
Widget build(BuildContext context) {
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
child: TextButton(
onPressed: () {
setState(() {
calculate();
});
},
child: Text(
'Button 001',
),
),
),
TextOutput(myValue: myValue),
],
),
);
}
}
class TextOutput extends StatelessWidget {
const TextOutput({
Key key,
#required this.myValue,
}) : super(key: key);
final int myValue;
#override
Widget build(BuildContext context) {
return Container(
child: Text(
myValue.toString(),
),
);
}
}
The part I want to extract into a separate widget:
Container(
child: TextButton(
onPressed: () {
setState(() {
calculate();
});
},
child: Text(
'Button 001',
),
),
),
Flutter offers VoidCallback and Function(x) (where x can be a different type) for callback-style events between child and parent widgets.
Simply You can pass Function onPressed; via constructor
Here is your Extracted Container widget:
class ExtractedContainer extends StatelessWidget {
final Function onPressed;
const ExtractedContainer({
Key key, #required this.onPressed,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: TextButton(
onPressed: () {
onPressed();
},
child: Text(
'Button 001',
),
),
);
}
}
And Here How to use it:
#override
Widget build(BuildContext context) {
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ExtractedContainer(onPressed: calculate,),
TextOutput(myValue: myValue),
],
),
);
}
Your full code example
import 'package:flutter/material.dart';
class MyApp2 extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Calculator(),
);
}
}
class Calculator extends StatefulWidget {
#override
_CalculatorState createState() => _CalculatorState();
}
class _CalculatorState extends State<Calculator> {
var myValue = 0;
void calculate() {
myValue = 12;
}
#override
Widget build(BuildContext context) {
return Container(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ExtractedContainer(onPressed: calculate,),
TextOutput(myValue: myValue),
],
),
);
}
}
class ExtractedContainer extends StatelessWidget {
final Function onPressed;
const ExtractedContainer({
Key key, #required this.onPressed,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: TextButton(
onPressed: () {
onPressed();
},
child: Text(
'Button 001',
),
),
);
}
}
class TextOutput extends StatelessWidget {
const TextOutput({
Key key,
#required this.myValue,
}) : super(key: key);
final int myValue;
#override
Widget build(BuildContext context) {
return Container(
child: Text(
myValue.toString(),
),
);
}
}
Setstate is related to the widget you want to refresh its state. If you extract it to another place, then setState refers to the state of the new widget.
In your case, the setState will only change the state of the container encapsulating your widget which you are trying to extract and its children, it doesn't migrate upward.
Unless, you look for the state of the widget you want, using exact type, and then trigger the state there, but this is overkill, a lot harder, requires more code, than what you currently have.
You can use VoidCallback on extract widget to get onPressed event
class MyContainer extends StatelessWidget {
final VoidCallback onTap;
const MyContainer({
Key? key,
required this.onTap,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
child: TextButton(
onPressed: onTap,
child: Text(
'Button 001',
),
),
);
}
}
And use like
MyContainer(
onTap: () {
print("tapped");
setState(() {
calculate();
});
},
),

Flutter web tabbar scroll issue with non primary scrollcontroller

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;
}
This has been accepted as a bug in flutter.
Pl follow for progress here: https://github.com/flutter/flutter/issues/83711
Note for other developers facing same issue.
To overcome the mentioned problem, I changed my design layout. Instead of tabbar view I used Navigationrail widget. This solved my problem.
NavigationRail widget allowed me to attach primary scroll controller to multiple widgets without giving me exception: "ScrollController attached to multiple scroll views."
Sample code.
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;
}