I'm at the beginning of learning Getx and I'm having the following problem: I have a ListView.builder with the CodeLine() widget, which is a widget where you can select it with an onLongPress. The idea here is to select a row but when I give onLongPress, all the rows are selected together.
class CodeEditor extends GetView<CodeEditorController> {
const CodeEditor({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
ScrollController scrollCode = ScrollController();
return Padding(
padding: const EdgeInsets.fromLTRB(0.0, 0.0, 10.0, 120.0),
child: ListView.builder(
controller: scrollCode,
itemCount: 10,
itemBuilder: (BuildContext context, int index){
return CodeLine();
}
)
);
}
}
In CodeLine I have isSelected variable to show on screen when it is selected or not and I change its value in CodeLineController controller
class CodeLine extends GetView<CodeLineController> {
CodeLine({Key? key}) : super(key: key);
@override
final controller = Get.put(CodeLineController());
@override
Widget build(BuildContext context) {
return GestureDetector(
child: GetX<CodeLineController>(
builder: (_){
return !_.isHidden ? Container(
color: _.isSelected ? const Color(0x327a7a7a) : Colors.transparent,
height: 35.0,
child: Row(
children: <Widget>[
SizedBox(
width: 25.0,
child: Text(
"1",
textAlign: TextAlign.end,
style: TextStyle(
color: codeLineTheme.hintColor,
fontSize: 15.0,
fontWeight: FontWeight.bold
)
)
),
const SizedBox(width: 7.5),
const Expanded(
child: SizedBox()
)
]
)
) : const SizedBox();
}
),
onLongPress: (){
controller.isSelected = !controller.isSelected;
}
);
}
}
In CodeLineController I have the isSelected variable as observable but when I change its boolean value, this value of all CodeLine instances is also changed, how can I change only the isSelected variable of a specific CodeLine?
class CodeLineController extends GetxController{
CodeLineController();
final _isHidden = false.obs;
get isHidden => _isHidden.value;
set isHidden(value) => _isHidden.value = value;
final _isSelected = false.obs;
get isSelected => _isSelected.value;
set isSelected(value) => _isSelected.value = value;
}
CodePudding user response:
When you call a class that you extend with GetxController with Get.put, only one of that object is found in the project. And you always define the same object in the CodeLine widget. So a change affects all of its widgets. You can solve your problem like this: Add Map inside CodeLineController. Save all CodeLine widgets you reproduced with ListView to the map with a special key.
class CodeLineController extends GetxController {
final RxMap<Key, bool> _map = <Key, bool>{}.obs;
void setKey(Key key, bool value) {
_map[key] = value;
}
void changeValue(Key key) {
if (_map[key] != null) {
_map[key] = !_map[key]!;
}
}
bool getValue(Key key) {
if (_map[key] != null) {
return _map[key]!;
} else {
return false;
}
}
...
}
It can be an int "index" value instead of the "key" in the Map or a unique data you want.
You can pass "key" as a parameter to the CodeLine class.
class CodeLine extends GetView<CodeLineController> {
final Key myKey;
CodeLine({
Key? key,
required this.myKey,
}) : super(key: key);
...
}
When creating the CodeLine class, pass the key as a parameter inside the ListView.
...
Key myKey;
return Padding(
...
itemBuilder: (BuildContext context, int index) {
myKey = GlobalKey();
controller.setKey(myKey, false);
return CodeLine(myKey: myKey);
},
...
onLongPress
...
onLongPress: () {
controller.changeValue(myKey);
},
...
This is how you can check
...
Container(
color: controller.getValue(myKey)
? const Color(0x327a7a7a)
: Colors.transparent,
...