Проблема с условием If Else в свойстве onPressed () в Dart / Flutter
Я хочу выделить кнопку из сетки, когда она нажата. К сожалению, при этом загорается вся колонка. Поскольку я новичок в flutter/Dart и кодировании в целом, я не уверен, что моя проблема - это отсутствие логики или что-то, чего я не знал бы об этом языке кодирования?
Домашняя страница:
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(() {});
},
),
),
);
}),
),
);
}),
),
],
),
),
);
}
}
Класс
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});
}
2 ответа
Довольно большой код, но я думаю, что проблема в том, что всякий раз, когда вы добавляете новый канал, вы даете ему существующий список кнопок. Попробуйте создать новый список кнопок при добавлении нового канала
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,
),
);
Сначала я рассмотрю некоторые улучшения логики программирования, а затем объясню, почему вы получаете неожиданные результаты.
1) Цвет actualColor внутри класса Button никогда не используется, удалите его.
2) Если каждая кнопка не будет иметь разные значения onColor и offColor, я предлагаю вынести эти две из класса Button или, по крайней мере, объявить их статическими. Вы напрасно создаете их экземпляры снова и снова, когда я предполагаю, что они вам понадобятся только один раз, это очень крошечное улучшение памяти (тем более, что у вас не будет тысяч кнопок), но, что более важно, удаление их из класса Button или создание Их static упростит чтение и понимание вашего кода, а также сократит количество аргументов, необходимых для передачи конструктору (снова более чистый код).
3) Ваши счетчики цикла "i" и "y", объявите их там, где они нужны. Уменьшите область видимости переменной так, чтобы она была видна только в той области, где она используется. Для этого существует множество... множество причин, короче говоря, когда используется больший объем, чем необходимо, код становится менее читаемым, сложным в обслуживании и с большей вероятностью будет ссылаться на непредусмотренные переменные.
Теперь о вашей актуальной проблеме. Проблема не в операторах if / else, она связана со списками и тем, как они обрабатываются в памяти. Возвращаясь к моему третьему пункту выше, всегда используйте наименьший возможный прицел. Вы указываете здесь свой btnList
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();
Позже вы добавляете тот же самый btnList на разные каналы здесь:
Text('CHANEL: $countChanel'),
IconButton(
icon: Icon(Icons.add),
onPressed: () {
chanelList.add(
Chanel(id: countChanel, buttonList: btnList));
countChanel++;
setState(() {});
},
Я предлагаю вернуться к основам и узнать в целом о массивах, списках и указателях. Вы также должны искать глубокое и неглубокое копирование. В приведенном выше блоке кода вы установили один и тот же btnList для всех элементов chanelList.
Допустим, вы создали список btnList, содержащий 4 элемента. Допустим, вы создаете список каналов, содержащий 2 элемента. Тогда channelList[ 0 ].buttonList[ 0 ].state всегда будет таким же, как channelList[ 1 ].buttonList[ 0 ].state, потому что они оба указывают на одну и ту же кнопку.
Чтобы получить это:
Быстрое и простое решение - это сделать что-то вроде этого:
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(() {});
},
),
PS Я бы также воздержался от ручного подсчета элементов списка, как вы, просто используйте предоставленный.length.