I am building a Flutter App where a List is shown using ListView. Which returns a ListTile with User Information. The ListTile
contains a leading
, title
and subtitle
with trailing
set as a ElevatedButton
.
I want to tap on the 'Invite Button' and change its color
, text
, and subtitle
of the ListTile
After tapping, it should look like this.
How can I do this? Here's the code that I wrote. But it's changing the state of every List Item.
class InviteFriends extends StatefulWidget {
const InviteFriends({Key? key}) : super(key: key);
@override
State<InviteFriends> createState() => _InviteFriendsState();
}
class _InviteFriendsState extends State<InviteFriends> {
bool isSelected = false;
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
}
UI Under ListView.builder
:
ListTile(
title: const Text('Haris'),
subtitle: const Text(
isSelected ? 'Invitation Sent' : 'Not Invited Yet',
),
leading: CircleAvatar(
backgroundImage: NetworkImage(
_userProfile!.profilePhoto.toString(),
),
),
trailing: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 0.0,
primary: isSelected ? Colors.orange : Colors.green,
side: BorderSide.none,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
),
child: const Text(
isSelected ? 'Invited': 'Invite',
),
onPressed: () {
setState(() {
isSelected = !isSelected;
});
},
),
);
I also tried Keys here in ListTile by using ValueKey(index)
but it didn't work either. What should I do? Thanks
CodePudding user response:
Bring out Tile as a separate StatefulWidget so that each has its own state. Do not modify State List.builder. And you use one isSelected field for all Tile, and you will all refer to this condition.
Please provide more code and I can help. So that I understand the full picture
CodePudding user response:
You need create different class for listtiles. Do as follows:
ListView.builder(
itemCount: 3,
shrinkWrap: true,
itemBuilder: (ctx, i) {
return MyListItems();
}))
then MyListItems.
class MyListItems extends StatefulWidget {
@override
MyListState createState() => MyListState();
}
class MyListState extends State<MyListItems> {
bool isSelected = false;
@override
Widget build(BuildContext context) {
return ListTile(
title: const Text('Haris'),
subtitle: Text(
isSelected ? "Invitation Sent" : 'Not Invited Yet',
),
leading: const CircleAvatar(
backgroundImage: NetworkImage(
'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQYtfZRhbGQtq2BapB2MXJfWIO2QriO5Wx3qQ&usqp=CAU'),
),
// use your image here
trailing: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 0.0,
primary: isSelected ? Colors.orange : Colors.green,
side: BorderSide.none,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
),
child: Text(
isSelected ? 'Invited' : 'Invite',
),
onPressed: () {
setState(() {
isSelected = !isSelected;
});
},
),
);
}}
CodePudding user response:
return ListView.builder(
itemCount: itemCount.length
itemBuilder: (BuildContext context, int index) {
return Friend(
//arg if available
);
});
class Friend extends StatefulWidget {
const Friend({Key? key}) : super(key: key);
@override
_FriendState createState() => _FriendState();
}
class _FriendState extends State<Friend> {
bool isSelected = false;
@override
Widget build(BuildContext context) {
//put ListTile detail here
return Row(
children: [
FlatButton(//deprecated but other buttons work
key: PageStorageKey('random num'),//if you are interested in keeping the state of the button while navigating
onPressed: () {
setState(() {
isSelected = !isSelected;
});
},
child: Text(isSelected ? "INVITED" : "INVITE"))
],
);
}
}
CodePudding user response:
You create a list say "i" (variable) to know the state of each tile and initilze all with false. On tap change there state to true.
final List<bool> selected = List.generate(20, (i) => false);
Pass the List "i" to the listview.builder like:-
itemBuilder: (BuildContext context, i)
See the full code
import 'package:flutter/material.dart';
class InviteFriends extends StatefulWidget {
const InviteFriends({Key? key}) : super(key: key);
@override
State<InviteFriends> createState() => _InviteFriendsState();
}
class _InviteFriendsState extends State<InviteFriends> {
bool isSelected = false;
@override
void initState() {
super.initState();
}
@override
void dispose() {
super.dispose();
}
final List<bool> selected = List.generate(20, (i) => false);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.only(top: 60),
child: ListView.builder(
// itemCount: i,
itemBuilder: (BuildContext context, i) {
return ListTile(
title: const Text('Haris'),
subtitle: Text(
selected[i] ? 'Invitation Sent' : 'Not Invited Yet',
),
leading: const CircleAvatar(
backgroundImage: AssetImage('assets/profile.gif'),
),
trailing: ElevatedButton(
style: ElevatedButton.styleFrom(
elevation: 0.0,
primary: selected[i] ? Colors.orange : Colors.green,
side: BorderSide.none,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10.0),
),
),
child: Text(
selected[i] ? 'Invited' : 'Invite',
),
onPressed: () {
setState(() => selected[i] = !selected[i]);
// setState(() {
// isSelected = !isSelected;
// });
}),
);
}),
),
);
}
}
Thank you
Output