- I have a variable which contains a map of widget in initState.
- One of this widget inside my variable is a gestureDetector who onTap change the value of a variable to change the animation of his child AnimatedAlign.
My problem is that when I active the onTap my animatedAlign stay static.
How should I do to be able to toogle the value of selected ?
import 'dart:developer';
import 'package:flutter/material.dart';
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
late Map<String, Map<String, List<Widget>>> data;
bool selected = false;
@override
void initState() {
// TODO: implement initState
data = {
"Animation and motion widgets": {
"AnimatedAlign": [
GestureDetector(
onTap: () {
setState(() {
selected = !selected;
});
log('$selected inside data');
},
child: Center(
child: Container(
width: 250.0,
height: 250.0,
color: Colors.red,
child: AnimatedAlign(
alignment:
selected ? Alignment.topRight : Alignment.bottomLeft,
duration: const Duration(seconds: 1),
curve: Curves.easeInCirc,
child: const FlutterLogo(size: 50.0),
),
),
),
)
],
},
"Animation and motion widgets2": {
"2widget1": [const Text('2widget1')],
"2widget2": [const Text('2widget2')]
}
};
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Widget catalog'),
),
body: PageView(
children: _getCategories(),
),
);
}
List<Widget> _getCategories() {
List<Widget> categories = [];
for (int i = 0; i < data.length; i++) {
categories.add(
PageView(
scrollDirection: Axis.vertical,
children: getWidgets(i),
),
);
}
return categories;
}
List<Widget> getWidgets(i) {
List<Widget> widgetPage = [];
widgetPage.add(Container(
color: Colors.red,
child: Center(
child: Text(data.keys.toList()[i]),
),
));
data[data.keys.toList()[i]]!.forEach((key, value) {
widgetPage.add(Container(
color: Colors.blue,
child: Padding(
padding: const EdgeInsets.only(top: 20.0),
child: Column(
children: [
Center(child: Text(key)),
Padding(
padding: const EdgeInsets.all(20.0),
child: Column(
children: value,
),
),
],
),
),
));
});
return widgetPage;
}
}
2
Answers
Everytime
setState()
is called,build()
is called in response to it and all the widgets are rebuilt. However,initState()
is called only when theStatefulWidget
(HomeScreen
in your case) is created.The problem in your code is that
AnimatedAlign
widget is built only once wheninitState()
is called. WhensetState()
is called, your code reuses the same instance ofAnimatedAlign
as stored indata
instead of rebuilding it.For your code to work, you will have to instantiate
data
map object inbuild()
instead ofinitState()
.There are other ways of achieving this but this is the simplest in order for you to understand what is happening here.
Create variable breaks the context chain, doesnt update the ui properly. Instead of create variable, you can create method that will be called inside build method. I am referring
And replace the use case
data
withdata()
.