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,
      ),
    );
  }
}

enter image description here


Solution 1: Jigar Patel

The variable curveList is a Map not a List of Maps, 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,
      ),
    );
  }
}

enter image description here