Can't update a widget state inside a List or a Map

Viewed 31

I'm trying to change the color of a text field that is created and added to a map through a function called addFields() but with no success.. Whereas when I add the Text Field directly without a function or a map the color changes as expected. I don't know what I'm doing wrong since I'm new to Flutter and programing in general.. If anyone can help I'd be very appreciated. thanks..

here is my code:

// ignore_for_file: avoid_print

import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  //
  @override
  void initState() {
    addFields();
    super.initState();
  }

  final Map<int, TextField> fields = {};
  //
  Color problemColor = const Color(0xff4caf50);
  Color noProblemColor = const Color(0xff4caf50);

  //
  void addFields() {
    final newTextField = TextField(
      decoration: InputDecoration(filled: true, fillColor: problemColor),
      onChanged: ((val) {
        setState(() {
          problemColor = const Color(0xfff44336);
        });
      }),
    );
    fields[0] = newTextField;
  }

  @override
  Widget build(BuildContext context) {
    print('problemColor = $problemColor');
    print('noProblemColor = $noProblemColor');
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            fields[0]!,
            TextField(
              decoration:
                  InputDecoration(filled: true, fillColor: noProblemColor),
              onChanged: ((val) {
                setState(() {
                  noProblemColor = const Color(0xfff44336);
                });
              }),
            )
          ],
        ),
      ),
    );
  }
}

1 Answers

Since you are using StatefulWidget to rebuild the UI, you should know some common functionality about how it works:

  1. The initState() method gets called only once when your page is getting build for the first time.

  2. The setState() method triggers rebuild of the StatefulWidget (build method) which rebuilds all components (widget) under build method.

  3. When you try to call setState() from TextField which is inside the map, it does not rebuild the color of TextField because it is outside the scope of build method.
    You can toggle the color of TextField which is inside the scope of build method through setState() method of TextField which is inside the map.

See this video to understand more.

Run this code to understand more

import 'package:flutter/material.dart';
class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  //
  @override
  void initState() {
    addFields();
    super.initState();
  }

  final Map<int, TextField> fields = {};
  //
  Color problemColor = const Color(0xff4caf50);
  Color noProblemColor = const Color(0xff4caf50);
  bool toggleColor = false;

  //
  void addFields() {
    final newTextField = TextField(
      decoration: InputDecoration(filled: true, fillColor: noProblemColor),
      onChanged: ((val) {
        setState(() {
          toggleColor = !toggleColor;
          problemColor = const Color(0xfff44336);
        });
      }),
    );
    fields[0] = newTextField;
  }

  @override
  Widget build(BuildContext context) {
    print('problemColor = $problemColor');
    print('noProblemColor = $noProblemColor');
    return Scaffold(
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            fields[0]!,
            TextField(
              decoration:
              InputDecoration(filled: true, fillColor: toggleColor ? problemColor : noProblemColor),
              onChanged: ((val) {
                setState(() {
                  noProblemColor = const Color(0xfff44336);
                });
              }),
            )
          ],
        ),
      ),
    );
  }
}
Related