0

I'm looking to highlight a button from a grid when it's pushed. Unfortunately, when I do so, the whole column lights up. As I'm new to flutter/Dart and to coding in general, I'm not sure if my problème is my lack of logic or something that I wouldn't know about that coding language?

The home page :

import 'package:flutter/material.dart';
import 'package:sequencer_n_lignes/utilities/sequence_class.dart';

class Home extends StatefulWidget {
  @override
  _Home createState() => _Home();
}

class _Home extends State<Home> {
  int i = 0, y = 0, indexTempo = 0;
  int countChanel = 0, countBtn = 0;
  bool isPlaying = false;
  List<Button> btnList = List();
  List<Chanel> chanelList = List();

  @override
  Widget build(BuildContext context) {
    return SafeArea(
      child: Scaffold(
        backgroundColor: Colors.grey[800],
        body: Column(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            Container(
              margin: EdgeInsets.fromLTRB(20, 10, 20, 10),
              decoration: BoxDecoration(
                  boxShadow: [
                    BoxShadow(
                      color: Colors.black,
                      blurRadius: 5,
                      spreadRadius: 1,
                    )
                  ],
                  color: Colors.grey[900],
                  border: Border.all(
                    color: Colors.white,
                    width: 0.5,
                  )),
              child: Row(
                children: <Widget>[
/*__________________________________________ADD/REMOVE BUTTONS___________________*/
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      IconButton(
                        icon: Icon(Icons.remove),
                        onPressed: () {
                          for (i = 0; i < 4; i++) {
                            btnList.removeLast();
                            countBtn--;
                          }
                          setState(() {});
                        },
                      ),
                      Text('BUTTONS: $countBtn'),
                      IconButton(
                        icon: Icon(
                          Icons.add,
                        ),
                        onPressed: () {
                          for (i = 0; i < 4; i++) {
                            btnList.add(Button(
                                id: countBtn,
                                onColor: Colors.blue,
                                offColor: Colors.grey[900],
                                state: false));
                            countBtn++;
                          }
                          setState(() {});
                        },
                      ),
                    ],
                  ), //
/*_________________________________________ADD/REMOVE CHANEL___________________*/
                  Row(
                    children: <Widget>[
                      IconButton(
                        icon: Icon(Icons.remove),
                        onPressed: () {
                          chanelList.removeLast();
                          countChanel--;
                          setState(() {});
                        },
                      ),
                      Text('CHANEL: $countChanel'),
                      IconButton(
                        icon: Icon(Icons.add),
                        onPressed: () {
                          chanelList.add(
                              Chanel(id: countChanel, buttonList: btnList));
                          countChanel++;
                          setState(() {});
                        },
                      ),
                    ],
                  ),
                  SizedBox(
                    width: 30,
                  ),
/*_____________________________________________CONTROLS___________________*/
                  Row(
                    children: <Widget>[
                      IconButton(
                        icon: Icon(
                          Icons.play_arrow,
                          color: (isPlaying) ? Colors.green : Colors.white,
                        ),
                        onPressed: () {
                          if (isPlaying)
                            isPlaying = false;
                          else
                            isPlaying = true;
                          setState(() {});
                        },
                      ),
                      IconButton(
                        icon: Icon(
                          Icons.stop,
                          color: (isPlaying) ? Colors.white : Colors.red[900],
                        ),
                        onPressed: () {
                          if (isPlaying)
                            isPlaying = false;
                          else
                            isPlaying = true;
                          setState(() {});
                        },
                      ),
                      IconButton(
                        icon: Icon(
                          Icons.refresh,
                          color: Colors.white,
                        ),
                        onPressed: () {
                          for (i = 0; i < chanelList.length; i++) {
                            for (y = 0; y < btnList.length; y++) {
                              chanelList[i].buttonList[y].state = false;
                            }
                          }
                          setState(() {});
                        },
                      ),
                      RaisedButton.icon(
                        icon: Icon(
                          Icons.details,
                          color: Colors.white,
                        ),
                        label: Text('OK'),
                        color: Colors.red[900],
                        onPressed: () {
                          setState(() {});
                        },
                      )
                    ],
                  ),
                ],
              ),
            ),
/*__________________________________________ GRID ___________________*/

            Column(
              children: List.generate(countChanel, (indexChanel) {
                return Padding(
                  padding: const EdgeInsets.fromLTRB(0, 5, 0, 5),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: List.generate(countBtn, (indexBtn) {
                      return Padding(
                        padding: EdgeInsets.fromLTRB(3, 0, 3, 0),
                        child: Container(
                          decoration: BoxDecoration(
                            boxShadow: [
                              BoxShadow(
                                color: Colors.black,
                                blurRadius: 0.1,
                                spreadRadius: 0.1,
                              ),
                            ],
                            border: Border.all(
                              color: Colors.white,
                              width: 0.5,
                            ),
                          ),
                          width: 80,
                          height: 80,
//THATS WHERE THE PROBLEM IS///////////////////////////
                              child: FlatButton(
    //                            child: Text(
    //                                '${chanelList[indexChanel].id.toString()} \n${chanelList[indexChanel].buttonList[indexBtn].id.toString()}\n$indexChanel-$indexBtn\n${chanelList[indexChanel].buttonList[indexBtn].state}'),
                                color: (chanelList[indexChanel]
                                        .buttonList[indexBtn]
                                        .state)
                                    ? chanelList[indexChanel]
                                        .buttonList[indexBtn]
                                        .onColor
                                    : chanelList[indexChanel]
                                        .buttonList[indexBtn]
                                        .offColor,
                                onPressed: () {
                                  if (chanelList[indexChanel]
                                      .buttonList[indexBtn]
                                      .state) {
                                    chanelList[indexChanel]
                                        .buttonList[indexBtn]
                                        .state = false;
                                  } else {
                                    chanelList[indexChanel]
                                        .buttonList[indexBtn]
                                        .state = true;
                                  }
                                  setState(() {});
                                },
                              ),
                            ),
                          );
                        }),
                      ),
                    );
                  }),
                ),
              ],
            ),
          ),
        );
      }
    }

The class

class Button {
  int id;
  Color onColor = Colors.red[900], offColor = Colors.grey[900];
  Color actualColor;
  bool state = false;

  Button({this.id, this.onColor, this.offColor, this.state});
}

class Chanel {
  int id;
  List<Button> buttonList;
  Chanel({this.id, this.buttonList});
}

Screen shot of the app

Théo
  • 51
  • 1
  • 7

2 Answers2

1

Pretty big code but I think the problem is that whenever you add a new Channel, you are giving it an existen buttonList. Try creating a new buttonList when you add a new Channel

chanelList.add(
    Chanel(
        id: countChanel,
        // Here is your problem, the reference to the buttons is the same
        // in all channels. Try creating new buttons for every channel
        buttonList: btnList,
    ),
);
Sebastian
  • 3,666
  • 2
  • 19
  • 32
1

I'll go over some of the programming logic improvements 1st and then explain why you are getting unexpected results.

1) Color actualColor inside Button class is never used, remove it.

2) Unless each button is going to have different onColor and offColor I suggest moving those two out of the Button class or at least declare them as static. You are needlessly instantiating them over and over again when I'm guessing you only need those once, this is a very tiny memory improvement (especially since you won't have thousands of buttons) but more importantly removing those from the Button class or making them static will make your code easier to read and understand, as well as cut down the number of arguments needed to pass to the constructor (again cleaner code).

3) Your loop counters "i" and "y", declare them where they are needed. Reduce the scope of the variable so that it is only visible in the scope where it is used. There are many... many reasons for doing so, in a nutshell when a larger scope than necessary is used, code becomes less readable, harder to maintain, and more likely to reference unintended variables.


Now for your actual problem. The problem isn't with if/else statements it has to do with lists and how they are handled in memory. Going back to my 3rd point above, always use the smallest scope possible. You are declaring your btnList here

class _Home extends State<Home> {
  int i = 0, y = 0, indexTempo = 0;
  int countChanel = 0, countBtn = 0;
  bool isPlaying = false;
  List<Button> btnList = List();
  List<Chanel> chanelList = List();

Later on you are adding that same btnList to different Channels here:

              Text('CHANEL: $countChanel'),
              IconButton(
                icon: Icon(Icons.add),
                onPressed: () {
                  chanelList.add(
                      Chanel(id: countChanel, buttonList: btnList));
                  countChanel++;
                  setState(() {});
                },

I suggest going back to basics and learn in general about arrays , lists and pointers. You should also search for deep and shallow copying. What you've done in the code block above is setting the same btnList to all of the chanelList items.

Lets say you create btnList that has 4 items. Lets say you create channelList that has 2 items. Then channelList[ 0 ].buttonList[ 0 ].state will always be the same as channelList[ 1 ].buttonList[ 0 ].state because they are both pointing to the same Button.

To get this:

ExampleOfWorkingCode

Quick and easy fix would be to do something like this:

              IconButton(
                icon: Icon(Icons.add),
                  onPressed: () {
                  List<Button> tmpBtnList = new List<Button>();  
                  for(int i=0; i<btnList.length; i++){
                    tmpBtnList.add(new Button(id: i,state: false));
                  }
                  chanelList.add(
                      Chanel(id: countChanel, buttonList: tmpBtnList));
                  countChanel++;
                  setState(() {});
                },
              ),

Complete code on DartPad.

PS I would also refrain from manually counting list items like you've done, just use the the provided .length.

Uroš
  • 1,428
  • 1
  • 12
  • 18