I am not sure I have built my code properly, but I was trying to save time on my first app project.

I have a page where I will be generating several selection buttons that I want text added to a list when you push this button. I chose not to build a traditional button but instead it goes to another widget that I can control the state with.

The problem i am having, is this selector button seems to be working fine. It changes and to verify it is being added to the list, I have it printing to the console and can see it.

The problem is my display container is not updating when I select the button.

I have tried a global key, but the problem is that since the buttons are getting generated, they share a global key. 1 button seems to be fine, I can pass the key along, but I am also limited in my knowledge of all this, so I could be doing something wrong.

My current path to the code is the following. Main Page -> Categories -> Sub Categories -> Page(digital in this case) -> Tags(the buttons).

import 'package:flutter/material.dart';
import 'package:onlytagsprod/widgets/tag.dart';

final digital = new GlobalKey<DigitalState>();

class Digital extends StatefulWidget {

  Digital({ Key key }) : super(key: key);

  @override
  DigitalState createState() => DigitalState();
}

class DigitalState extends State<Digital> {

  final postRefresh = ChangeNotifier();

  bool digitalSelected = false;
  List digitalHash = new List();
  String displays;

  @override
  void initState() {
    super.initState();
  }

  callback() {
    setState(() {
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        backgroundColor: Color(0xff0E0E0F),
        appBar: AppBar(
          iconTheme: IconThemeData(
            color: Color(0xffff9900),
          ),
          centerTitle: true,
          backgroundColor: Colors.black,
          title: Row(
            mainAxisAlignment: MainAxisAlignment.center,
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              Text(
                "#",
                style: TextStyle(
                    fontSize: 25,
                    color: Color(0xffff9900),
                    fontFamily: 'Dokyo'),
              ),
              Text(
                "digital",
                style: TextStyle(color: Colors.white, fontFamily: 'Dokyo'),
              )
            ],
          ),
        ),
        body: Column(children: <Widget>[
          Expanded(
            flex: 3,
            child: Container(
                child: Row(
                  children: <Widget>[
//Display the List here*********************************************
                for (var digitalHashs in digitalHash)
                Text(
                digitalHashs,
                style: TextStyle(color: Colors.white, fontSize: 20))
                  ],
                ),
                color: Colors.blue),
          ),
          Expanded(
            flex: 6,
            child: Container(
              color: Colors.black,
              child: ListView(
                padding: EdgeInsets.fromLTRB(25, 5, 25, 5),
                children: <Widget>[
                  Tag(
                    tag: "#Digital",
                    isSelected: digitalSelected,
                    list: digitalHash,
                  ),
                  Tag(
                    tag: "#DigitalLife",
                    isSelected: digitalSelected,
                    list: digitalHash,
                  ),
                ],
              ),
            ),
          )
        ]));
  }
}

This display page i want to be able to add as many Tag options as I want.

This is the Tag Page.

import 'package:flutter/material.dart';
import 'package:onlytagsprod/subpages/digital.dart';

class Tag extends StatefulWidget {
  final String tag;
  bool isSelected;
  List list;
  Function(List) callback;

  Tag(
      {Key key,
        @required this.tag,
        @required this.isSelected,
        this.list,
      this.callback})
      : super(key: key);

  @override
  _TagState createState() => _TagState();
}

class _TagState extends State<Tag> with SingleTickerProviderStateMixin {
  AnimationController _animationController;

  @override
  void initState() {
    super.initState();
    _animationController =
        AnimationController(vsync: this, duration: Duration(milliseconds: 300));
  }

  @override
  void dispose() {
    super.dispose();
    _animationController.dispose();
  }

  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.fromLTRB(0, 5, 0, 5),
      height: 50,
      decoration: BoxDecoration(
          color: widget.isSelected ? Color(0xffff9900) : Colors.black,
          border: Border.all(color: Colors.white),
          borderRadius: BorderRadius.circular(10)),
      child: InkWell(
        onTap: () {
          _handleOnPressed();
        },
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: <Widget>[
            Container(
                padding: EdgeInsets.fromLTRB(20, 0, 0, 0),
                alignment: Alignment.centerLeft,
                child: Text(
                  widget.tag,
                  style: TextStyle(
                      fontSize: 20,
                      color: widget.isSelected ? Colors.black : Colors.white,
                      fontFamily: 'Dokyo'),
                )),
            Container(
                padding: EdgeInsets.fromLTRB(0, 0, 20, 0),
                child: AnimatedIcon(
                  icon: AnimatedIcons.home_menu,
                  progress: _animationController,
                  color: widget.isSelected ? Colors.black : Colors.white,
                ))
          ],
        ),
      ),
    );
  }

  void _handleOnPressed() {
    setState(() {
      widget.isSelected = !widget.isSelected;
      widget.isSelected
          ? _animationController.forward()
          : _animationController.reverse();
      widget.isSelected ? widget.list.add(widget.tag) : widget.list.remove(widget.tag);
      print(widget.list);
    });
  }
}

The code has gotten a bit sloppy since I have tried every way I know how to address the state change... so I am aware of the unneeded stuff.

I am just at my newbie wits end


Solution 1: Abion47

The easiest way to get state changes to a parent or ancestor is via a callback method. That being said, you already define a callback field in the Tag class, but neither the build method in the parent widget nor the _TagState class is referencing it at all.

All you should need to do is change the _handleOnPressed method to execute the callback:

void _handleOnPressed() {
  ...
  widget.callback?.call(widget.list);
}

and change the constructors for Tag in the parent widget to assign them:

Tag(
  tag: "#DigitalLife",
  isSelected: digitalSelected,
  list: digitalHash,
  callback: (list) => setState(() => digitalHash = list),
),