Reputation: 3229
I'm trying to create a horizontal listview of containers that change colour on tap. I want to make "pressed" and "unpressed" such that only one container can be pressed at a time, if another container is pressed the former pressed container repaints to the unpressed color. I was going to go about this using a stateful widget with a callback function that uses the setState method to change the colour and update a map that contains the colour states of each container.
To start off I just wanted to print to console of the container I was pressing, but it seems like it pressed multiple containers at once. How can I fix this? If there's a better way to go about changing colours of containers please do share.
Container widget code:
class Box extends StatefulWidget {
int color;
int index;
Function callback;
Box(this.color, this.index, this.callback);
@override
_BoxState createState() => _BoxState(color, index, callback);
}
class _BoxState extends State<Box> {
int color;
int index;
Function callback;
_BoxState(this.color, this.index, this.callback);
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: callback(index),
child: Container(
width: 150.0,
decoration: new BoxDecoration(
color: Color(color),
shape: BoxShape.circle,
),
child: Center(child: Text("${index + 1}"))));
}
}
Page where I implement horizontal listview:
class TestPage extends StatelessWidget {
int _selected;
var pressStates = {
//Color states of each container
//unpressed = 0xFFD0D0DE
//pressed = 0xFF8A2BE2
1: 0xFFD0D0DE,
2: 0xFFD0D0DE,
3: 0xFFD0D0DE,
4: 0xFFD0D0DE,
5: 0xFFD0D0DE,
6: 0xFFD0D0DE,
7: 0xFFD0D0DE,
8: 0xFFD0D0DE,
9: 0xFFD0D0DE,
10: 0xFFD0D0DE,
11: 0xFFD0D0DE,
12: 0xFFD0D0DE,
};
@override
Widget build(BuildContext context) {
var _width = MediaQuery.of(context).size.width;
callback(int index) {
_selected = index + 1;
print("tapped ${index + 1}, state: ${_selected}");
}
final _test = ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: pressStates.length,
itemBuilder: (context, index) {
return Box(pressStates[index + 1], index, callback);
});
return new Scaffold(
backgroundColor: Colors.black54,
body: new Container(height: 300.0, width: _width, child: _test),
);
}
}
Console output:
I/flutter (11600): tapped 1, state: 1
I/flutter (11600): tapped 2, state: 2
I/flutter (11600): tapped 3, state: 3
I/flutter (11600): tapped 4, state: 4
I/flutter (11600): tapped 5, state: 5
Upvotes: 0
Views: 970
Reputation: 20558
Your code will print ok if you just replace the onTap
property with
onTap: () { callback(index); },
But you should refactor your code to make the Test class a StatefulWidget because it holds the state for the selected circle. And make the Box Stateless.
import 'package:flutter/material.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter Demo',
theme: new ThemeData(
primarySwatch: Colors.blue,
),
home: TestPage(),
);
}
}
class TestPage extends StatefulWidget {
@override
TestPageState createState() {
return new TestPageState();
}
}
class TestPageState extends State<TestPage> {
int _selected;
var selectedColor = 0xFFD000DE;
var unselectedColor = 0xFFD0D0DE;
callback(int index) {
_selected = index;
setState(() {});
print("tapped ${index + 1}, state: ${_selected}");
}
@override
Widget build(BuildContext context) {
var _width = MediaQuery.of(context).size.width;
final _test = ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 12,
itemBuilder: (context, index) {
return Box(
_selected == index ? selectedColor : unselectedColor,
index,
callback,
);
});
return new Scaffold(
backgroundColor: Colors.black54,
body: Container(height: 300.0, width: _width, child: _test),
);
}
}
class Box extends StatelessWidget {
final int color;
final int index;
final Function callback;
Box(this.color, this.index, this.callback);
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
callback(index);
},
child: Container(
width: 150.0,
decoration: new BoxDecoration(
color: Color(color),
shape: BoxShape.circle,
),
child: Center(child: Text("${index + 1}"))));
}
}
Upvotes: 1