I'm still learning flutter and having difficulty wrapping my mind around dynamically using setstate with a multi-dim array (Map).
I am attempting to update individual values (width, height, color) of a simple container within a Gridview.build using random and a FAB.
If I do just a single random element outside of a gridview, it works fine.
The final output of this class is to cycle through every Curve.* there is in flutter and output a random shape in a gridview pattern. It will change each time the FAB button is pressed.
The current error is me trying to figure out how to add values to a Map...if they are being added correctly through setstate in the first place:
Help me, Obi-Wan, you're my only hope.
The method '[]' was called on null.
Receiver: null
Tried calling: []("width")
Here is my code:
import 'dart:math';
import 'package:flutter/material.dart';
class AnimatedContainerPage extends StatefulWidget {
@override
_AnimatedContainerPageState createState() => _AnimatedContainerPageState();
}
class _AnimatedContainerPageState extends State<AnimatedContainerPage> {
double _width = 200;
double _height = 200;
Color _color = Colors.red;
BorderRadiusGeometry _borderRadius = BorderRadius.circular(16);
final random = Random();
//Once working add all the Curves
var curves = [
Curves.bounceIn,
Curves.bounceInOut,
Curves.bounceOut,
Curves.decelerate,
Curves.ease,
Curves.easeIn,
Curves.easeInBack
];
Map curveList = {
'curve': Curves.bounceIn,
'width': 200,
'height': 200,
'color': Colors.red,
'borderrad': BorderRadius.circular(16),
};
void _randomize() {
setState(() {
//loop through curve list and add random params to each curve
for (int i = 0; i < curves.length; i++) {
_width = random.nextInt(300).toDouble();
_height = random.nextInt(300).toDouble();
_color = Color.fromRGBO(
random.nextInt(256), random.nextInt(256), random.nextInt(256), 1);
_borderRadius = BorderRadius.circular(random.nextInt(100).toDouble());
curveList.addAll({
'curve': curves[i],
'width': _width,
'height': _height,
'color': _color,
'borderrad': _borderRadius,
});
// print(curveList);
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('AnimatedContainer'),
),
body: Center(
child: GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3),
itemCount: curveList.length,
itemBuilder: (BuildContext context, int index) {
print('index is $index and curves i is ${curves[index]}');
return AnimatedContainer(
width: curveList[index]['width'],
height: curveList[index]['height'],
decoration: BoxDecoration(
color: curveList[index]['color'],
borderRadius: curveList[index]['borderradius'],
),
duration: Duration(seconds: 1),
curve: curves[index],
padding: EdgeInsets.all(10),
);
},
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.play_arrow),
onPressed: _randomize,
),
);
}
}
Solution 1: Jigar Patel
The variable curveList
is a Map
not a List
of Map
s, so change to this.
return AnimatedContainer(
width: curveList['width'],
height: curveList['height'],
decoration: BoxDecoration(
color: curveList['color'],
borderRadius: curveList['borderradius'],
),
duration: Duration(seconds: 1),
curve: curves[index],
padding: EdgeInsets.all(10),
);
Edit:
Actually you need curveList
to be a List<Map>
(list of maps) for your use case. So you need to make changes like so.
List<Map> curveList = [
{
'curve': Curves.bounceIn,
'width': 200.0,
'height': 200.0,
'color': Colors.red,
'borderrad': BorderRadius.circular(16),
}
];
void _randomize() {
setState(() {
//loop through curve list and add random params to each curve
curveList.clear();
for (int i = 0; i < curves.length; i++) {
_width = random.nextInt(300).toDouble();
_height = random.nextInt(300).toDouble();
_color = Color.fromRGBO(
random.nextInt(256), random.nextInt(256), random.nextInt(256), 1);
_borderRadius = BorderRadius.circular(random.nextInt(100).toDouble());
curveList.add({
'curve': curves[i],
'width': _width,
'height': _height,
'color': _color,
'borderrad': _borderRadius,
});
// print(curveList);
}
});
}
and keep this part as it is
width: curveList[index]['width'],
height: curveList[index]['height'],
decoration: BoxDecoration(
color: curveList[index]['color'],
borderRadius: curveList[index]['borderradius'],
),
Solution 2: Gumdum
Thanks much @Jigar Patel! The error was the List and adding clear() is a smart move. Below is the final usecase code. If you want to use this in anything, make sure to put in a height check for border radius first, as sometimes the animation will have a negative height.
mport 'dart:math';
import 'package:flutter/material.dart';
class AnimatedContainerPage extends StatefulWidget {
@override
_AnimatedContainerPageState createState() => _AnimatedContainerPageState();
}
class _AnimatedContainerPageState extends State<AnimatedContainerPage> {
double _width = 200;
double _height = 200;
Color _color = Colors.red;
BorderRadiusGeometry _borderRadius = BorderRadius.circular(16);
final random = Random();
var curves = [
Curves.bounceIn,
Curves.bounceInOut,
Curves.bounceOut,
Curves.decelerate,
Curves.ease,
Curves.easeIn,
Curves.easeInBack,
Curves.easeInCirc,
Curves.easeInCubic,
Curves.easeInExpo,
Curves.easeInOut,
Curves.easeInOutBack,
Curves.easeInOutCirc,
Curves.easeInOutCubic,
Curves.easeInOutCubicEmphasized,
Curves.easeInOutExpo,
Curves.easeInOutQuad,
Curves.easeInOutQuart,
Curves.easeInOutQuint,
Curves.easeInOutSine,
Curves.easeInQuad,
Curves.easeInQuart,
Curves.easeOutSine,
Curves.elasticIn,
Curves.elasticInOut,
Curves.elasticOut,
Curves.fastLinearToSlowEaseIn,
Curves.fastOutSlowIn,
Curves.linear,
Curves.linearToEaseOut,
Curves.slowMiddle
];
List<Map> curveList = [
{
'curve': Curves.bounceIn,
'width': 200.0,
'height': 200.0,
'color': Colors.red,
'borderrad': BorderRadius.circular(16),
}
];
void _randomize() {
setState(() {
//loop through curve list and add random params to each curve
curveList.clear();
for (int i = 0; i < curves.length; i++) {
_width = random.nextInt(300).toDouble();
_height = random.nextInt(300).toDouble();
_color = Color.fromRGBO(
random.nextInt(256), random.nextInt(256), random.nextInt(256), 1);
_borderRadius = BorderRadius.circular(random.nextInt(100).toDouble());
curveList.add({
'curve': curves[i],
'width': _width,
'height': _height,
'color': _color,
'borderrad': _borderRadius,
});
// print(curveList);
}
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('AnimatedContainer'),
),
body: Center(
child: GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3),
itemCount: curveList.length,
itemBuilder: (BuildContext context, int index) {
return Stack(
alignment: Alignment.center,
children: [
AnimatedContainer(
width: curveList[index]['width'],
height: curveList[index]['height'],
decoration: BoxDecoration(
color: curveList[index]['color'],
borderRadius: curveList[index]['borderrad'],
),
duration: Duration(seconds: 4),
curve: curves[index],
padding: EdgeInsets.all(10),
),
Container(
width: 100,
child: Text(
curves[index].toString(),
style: TextStyle(
color: Colors.white,
backgroundColor: Colors.black,
fontWeight: FontWeight.bold,
),
),
),
],
);
},
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.play_arrow),
onPressed: _randomize,
),
);
}
}