I am fetching certain details from firebase and showing them in the form of card, with the help of ListView.Builder. Now, upon tapping a specific card I want to change its border colour to green. I have tried using the flag variable in the setState but it sets the border colour for every card to green. Someone pls have a look at the code I've pasted, and let me know what should be done.This is the image of the UI
Thank You:)
StreamBuilder<QuerySnapshot>(
stream: collectionTests.snapshots(),
builder: (context, snapshot) {
if (snapshot.hasError) {
return const Text("Something went wrong");
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
} else {
final myDocs = snapshot.data!.docs;
try {
return ListView.builder(
itemCount: myDocs.length,
itemBuilder: (context, index) {
return Padding(
padding: const EdgeInsets.fromLTRB(17, 11, 17, 11),
child: InkWell(
onTap: () {},
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
side: const BorderSide(
color: Colors.white,
),
),
child: ListTile(
contentPadding: const EdgeInsets.all(8),
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
myDocs[index]['name'],
style: const TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
Card(
color: Colors.indigo,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
myDocs[index]['price'],
style: const TextStyle(
color: Colors.white,
fontStyle: FontStyle.italic,
fontSize: 20,
),
),
),
)
],
),
subtitle: Padding(
padding: const EdgeInsets.fromLTRB(8, 8, 12, 8),
child: Text(
myDocs[index]['description'],
style: const TextStyle(
fontSize: 18,
),
),
),
),
),
),
);
},
);
} catch (e) {
return const Center(
child: Card(
child: Text(
'Something went wrong, please check your connection',
style: TextStyle(
fontSize: 18,
color: Colors.black,
),
),
),
);
}
}
},
),
CodePudding user response:
Extract your widget into a new stateful class and call the class inside the ListView.
main.dart
import 'package:flutter/material.dart';
import 'package:stackoverflow/custom_card.dart';
void main(){
runApp(MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: ListView.builder(
itemCount: 5,
itemBuilder: (context, i){
return CustomCard();
},
),
),
);
}
}
custom_card.dart
import 'package:flutter/material.dart';
class CustomCard extends StatefulWidget {
const CustomCard({Key? key}) : super(key: key);
@override
_CustomCardState createState() => _CustomCardState();
}
class _CustomCardState extends State<CustomCard> {
Color borderColor = Colors.black;
@override
Widget build(BuildContext context) {
return SizedBox(
width: double.infinity,
height: 100,
child: GestureDetector(
onTap: (){
setState(() {
borderColor = Colors.green;
});
},
child: Card(
color: borderColor,
),
),
);
}
}
CodePudding user response:
Firstly, you need to define a list that contains bool variables out of build method. These variables will decide whether the border of relevant card is white or green.
List<bool> bordersColors = [];
Then in your listview like this;
return ListView.builder(
itemCount: myDocs.length,
itemBuilder: (context, index) {
bordersColors.add(false);
return Padding(
padding: const EdgeInsets.fromLTRB(17, 11, 17, 11),
child: InkWell(
onTap: () {
setState((){
bordersColors[index] = true;
})
},
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
side: const BorderSide(
color: bordersColors[index] ? Colors.green : Colors.white,
),
),
child: ListTile(
contentPadding: const EdgeInsets.all(8),
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
myDocs[index]['name'],
style: const TextStyle(
fontSize: 22,
fontWeight: FontWeight.bold,
),
),
Card(
color: Colors.indigo,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
myDocs[index]['price'],
style: const TextStyle(
color: Colors.white,
fontStyle: FontStyle.italic,
fontSize: 20,
),
),
),
)
],
),
subtitle: Padding(
padding: const EdgeInsets.fromLTRB(8, 8, 12, 8),
child: Text(
myDocs[index]['description'],
style: const TextStyle(
fontSize: 18,
),
),
),
),
),
),
);
},
);
} catch (e) {
return const Center(
child: Card(
child: Text(
'Something went wrong, please check your connection',
style: TextStyle(
fontSize: 18,
color: Colors.black,
),
),
),
);