Flutter ListTile title name from json - android

I am trying to display both names of a person as a title in listtile flutter. This is the sample json file
var users = const [
{
"first_name": "melissa",
"last_name": "fleming",
"phone_number": "0740-304-475"
},
{
"first_name": "christoffer",
"last_name": "christiansen",
"phone_number": "05761325"
},
{
"first_name": "valtteri",
"last_name": "pulkkinen",
"phone_number": "041-829-79-61"
}
]
This is the flutter code
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text(
"List of Customers",
),
body: ListView.separated(
itemCount: users.length,
separatorBuilder: (context, index) => Divider(),
itemBuilder: (BuildContext context, int index) {
var user = users[index];
return ListTile(
title: Text(user['first_name']),
isThreeLine: true,
);
},
),
);
}
How can I pass both names to this part
title: Text(user['first_name']),

You can use for in loop and store the value in a String
for(var i in users){
String name = i['first_name'] + " "+ i['last_name'];
print(name);}
ListView.separated(
itemCount: users.length,
separatorBuilder: (context, index) => Divider(),
itemBuilder: (BuildContext context, int index) {
var user = users[index];
return ListTile(
title: Text(name),
isThreeLine: true,
);
},
),

there are two ways you can do it.
First Approach : if you want to show full name as title :
title : Text("$users[0]['first_name'] $users[0]['last_name']")
Second Approach : if you want to show first name and last name separately use subtitle :
ListTile(
leading: const Icon(Icons.flight_land),
title: const Text($users[0]['first_name']),
subtitle: Text($users[0]['last_name']),
onTap: () { /* react to the tile being tapped */ }
)

Related

hi why my list item turn null in the futurebuilder of flutter?

Hi in my flutter app have FutureBuilder that return listview, my list listview create some button for update the hive table. when I click the first time on one of buttons everything is run smoothly, but when I click on same button again my hive key turn to null and program show my this error: "type 'Null' is not a subtype of type 'int' "
I write print all over my code but still I do not get it why the key turn null from the second time.
How can I Correct this? please help my.
my Futurebuilder body is:
FutureBuilder<List>(
future: controller.showTaskList(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return SizedBox(
height: Get.height,
child: const Center(
child: CircularProgressIndicator(),
),
);
default:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
List data = snapshot.data ?? [];
return ListView.separated(
scrollDirection: Axis.vertical,
physics:
const BouncingScrollPhysics(),
shrinkWrap: true,
itemCount: data.length,
itemBuilder: (context, index) {
// controller.taskIconCheckList
// .clear();
for (int i = 0;
i < data.length;
i++) {
if (data[i].status == true) {
controller.taskIconCheckList
.add(true.obs);
} else {
controller.taskIconCheckList
.add(false.obs);
}
}
return ListTile(
leading: Obx(
() => PageTransitionSwitcher(
transitionBuilder: (
child,
primaryAnimation,
secondaryAnimation,
) {
return SharedAxisTransition(
animation:
primaryAnimation,
secondaryAnimation:
secondaryAnimation,
transitionType:
SharedAxisTransitionType
.horizontal,
fillColor:
Colors.transparent,
child: child,
);
},
duration: const Duration(
milliseconds: 800),
child: controller
.taskIconCheckList[
index]
.value
? SizedBox(
child: IconButton(
icon: const Icon(
Icons
.check_circle_rounded,
color: Colors
.lightGreenAccent,
),
onPressed: () {
controller
.functionTaskIconCheckList(
index,
);
print('طول دیتا');
print(data.length.toString());
print('مقدار ایندکس');
print(index.toString());
print('مقدار کلید');
print(data[index].key.toString());
print(data[index].taskText.toString());
controller
.updateStatusTask(
index,
data[index]
.key); // here when i first click // return key currectly, but after that show null and updatestatusetask not run and show error.
},
),
)
: IconButton(
onPressed: () {
controller
.functionTaskIconCheckList(
index,
);
print('طول دیتا');
print(data.length.toString());
print('مقدار ایندکس');
print(index.toString());
print('مقدار کلید');
print(data[index].key.toString());
print(data[index].taskText.toString());
controller
.updateStatusTask(
index,
data[index]
.key); // here when i first click // return key currectly, but after that show null and updatestatusetask not run and show error.
},
icon: const Icon(
Icons
.radio_button_unchecked_outlined,
color: Colors.red,
),
),
),
),
title: Text(data[index].taskText,
style: normalTextForCategory),
subtitle: Text(
data[index]
.date
.toString()
.substring(0, 10),
textDirection:
TextDirection.ltr,
textAlign: TextAlign.right,
style: normalTextForSubtitle,
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
onPressed: () {
myDefaultDialog(
'هشدار',
'آیا از حذف این گزینه اطمینان دارید؟',
'بله',
'خیر',
() {
Get.back();
mySnakeBar(
'',
'گزینه مورد نظر با موفقیت حذف شد.',
Icons
.warning_amber_rounded,
Colors.yellow);
},
);
},
icon: const Icon(
Icons.delete),
color: Colors.redAccent,
),
IconButton(
onPressed: () {
Get.offNamed(
Routs.editTaskScreen,
arguments: 'edit');
},
icon: const Icon(
Icons.edit_calendar,
color:
Colors.yellowAccent,
),
),
],
),
);
},
separatorBuilder:
(BuildContext context,
int index) {
return const Divider(
height: 2,
color: Colors.white70,
);
},
);
}
}
},
),
this is my functionTaskIconCheckList form controller:
functionTaskIconCheckList(int index) {
taskIconCheckList[index].value = !taskIconCheckList[index].value;}
and this the updatestatusetask function
updateStatusTask(int index,int taskKey) async {
print('در تابع آپدیت ایندکس هست: ${index.toString()}');
print('در تابع آپدیت کی هست: ${taskKey.toString()}');
var taskBox = await Hive.openBox('task');
var filterTask = taskBox.values.where((task) => task.key == taskKey).toList();
Task task = Task(
filterTask[0].taskText,
filterTask[0].date,
taskIconCheckList[index].value,
filterTask[0].deleteStatus,
null,
null,
filterTask[0].taskCatId,
filterTask[0].userId);
await taskBox.put(taskKey, task);}
and this is my showtasklist function:
Future<List> showTaskList() async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
var taskBox = await Hive.openBox('task');
var filterTask = taskBox.values
.where((task) => task.userId == sharedPreferences.getInt('key'))
.toList();
return filterTask;}
this is my model:
#HiveType(typeId: 2)
class Task extends HiveObject{
#HiveField(0)
String taskText;
#HiveField(1)
DateTime date;
#HiveField(2)
bool status;
#HiveField(3)
bool deleteStatus;
#HiveField(4)
int taskCatId;
#HiveField(5)
int userId;
#HiveField(6)
User? user;
#HiveField(7)
TaskCat? taskCat;
Task(this.taskText, this.date, this.status, this.deleteStatus, this.user,
this.taskCat, this.taskCatId, this.userId);
}
One possible solution would be to wait for the Future function to finish and then load the list. If it tries to load the list early before finishing up the Future function, it might presume the value to be null.
Hope this helps.
Still I do not know what is cause this problem, But I found an alternative temporary solution. I create temporary Int list. then just before the return listTile in the futureBuilder body, I write the Loop and save all of the key in that list. finally instead of pass the "data[index].key." I pass my key from that temporary Int list. so everything work fine now
this is my part of code change from before, but still I want know main solution.
return ListView.separated(
scrollDirection: Axis.vertical,
physics:
const BouncingScrollPhysics(),
shrinkWrap: true,
itemCount: data.length,
itemBuilder: (context, index) {
// controller.taskIconCheckList
// .clear();
for (int i = 0;
i < data.length;
i++) {
Get.find<
HomeScreenController>()
.taskKey.add(data[i].key);
if (data[i].status == true) {
Get.find<
HomeScreenController>()
.taskIconCheckList
.add(true.obs);
} else {
Get.find<
HomeScreenController>()
.taskIconCheckList
.add(false.obs);
}
}
return ListTile(

how can use future in the listview flutter?

I have future function and I want show this in the listview.seprator, but the listview do not get the future value. how can i fix this?
this is my code:
my hive class:
#HiveType(typeId: 3)
class TaskCat extends HiveObject{
#HiveField(0)
String catName;
#HiveField(1)
int userId;
#HiveField(2)
User? user;
TaskCat(this.catName,this.user,this.userId);
}
This is my function:
Future<List> showCategoryInHome() async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
var taskCatBox = await Hive.openBox('taskCat');
var filtertaskCat = taskCatBox.values
.where(
(TaskCat) => TaskCat.userId == sharedPreferences.getInt('key'))
.toList();
return filtertaskCat;
}
and this is my listview code:
FutureBuilder(
future: controller.showCategoryInHome(),
builder: (context, snapshot) {
Future<List> test = controller.showCategoryInHome();
return ListView.separated(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: 11 , // here currently I set the fix value but I want the length of my list
itemBuilder: (context, index) {
return TextButton(
onPressed: () {
},
child: Text(
test[index].[catName], // and here not working too bucouse the list is future
style: normalTextForCategory,
),
);
},
separatorBuilder:
(BuildContext context, int index) {
return const VerticalDivider(
width: 15,
color: Colors.transparent,
);
},
);
},
)
Try this:
FutureBuilder<List>(
future: controller.showCategoryInHome(),
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return Text('Loading....');
default:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
List data = snapshot.data ?? [];
return ListView.separated(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount:data.length,
itemBuilder: (context, index) {
return TextButton(
onPressed: () {},
child: Text(
data[index]['catName'],
style: normalTextForCategory,
),
);
},
separatorBuilder: (BuildContext context, int index) {
return const VerticalDivider(
width: 15,
color: Colors.transparent,
);
},
);
}
}
},
),
Inside your Future you have builder, where you can access to your future when it ready via snapshot.
I've added the precise type where to make the use of Futurebuilder easier.
Future<List<TaskCat>> showCategoryInHome() async {
SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
var taskCatBox = await Hive.openBox('taskCat');
var filtertaskCat = taskCatBox.values
.where(
(TaskCat) => TaskCat.userId == sharedPreferences.getInt('key'))
.toList();
return filtertaskCat;
}
And adjust your Futurebuilder to the following:
FutureBuilder<List<TaskCat>>(
future: controller.showCategoryInHome(),
builder: (context, snapshot) {
// Check if your future has finished
if(snapshot.hasData) {
// Here you have the result of your future, which is a List<TaskCat>
final tasks = snapshot.data;
return ListView.separated(
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemCount: tasks.length,
itemBuilder: (context, index) {
return TextButton(
onPressed: () {
},
child: Text(
tasks[index].catName,
style: normalTextForCategory,
),
);
},
separatorBuilder:
(BuildContext context, int index) {
return const VerticalDivider(
width: 15,
color: Colors.transparent,
);
},
);
} else {
// Here you can show e.g. a CircularProgressIndicator
return SizedBox();
}
},
)

Flutter chat app on Firebase, StreamBuilder reloads blinking and calls on null value when ListView is created

I'm making a FreeLancer app with a chat function. First, I want the chat list that renders chat tiles from Firebase so I use GetX Stream (is this like streamBuilder?) to render the chat tile representing, and in that chat tile (I'm using ListTile) the subtitle text is pulled from FireStore from the latest message using StreamBuilder
Chat List Screen
final user = FirebaseAuth.instance.currentUser;
return user == null
? const Center(
child: Text('Please login to use Chat'),
)
: Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () async {
ChatService().addRoom(randomString());
},
child: const Icon(FontAwesomeIcons.solidMessage),
),
appBar: AppBar(
title: const Text('Chats'),
centerTitle: true,
),
body: GetX<ChatController>(
init: ChatController(),
builder: (roomList) {
return ListView.builder(
itemCount: roomList.rooms.length,
itemBuilder: (context, index) {
return ChatTile(roomList.rooms[index]);
},
);
},
),
Chat Tile
final db = FirebaseFirestore.instance.collection('Rooms').doc(room.roomId);
final stream = db.snapshots();
var roomName = 'Loading...';
return StreamBuilder(
stream: stream,
builder: (context, snapshot) {
final roomInfo = snapshot.data as dynamic;
return Column(
children: [
InkWell(
onTap: () {},
child: SizedBox(
height: MediaQuery.of(context).size.height * 0.08,
child: Center(
child: ListTile(
contentPadding: const EdgeInsets.symmetric(horizontal: 10),
leading: const FlutterLogo(size: 50),
title: Text(roomInfo['roomName']),
subtitle: LastMessage(room.roomId),
trailing: Text(timeago.format(
(roomInfo['lastestMsg'] as Timestamp).toDate())),
),
),
),
),
const Divider()
],
);
},
);
Latest Message
final db = FirebaseFirestore.instance.collection('Rooms').doc(roomId);
final stream = db
.collection('message')
.orderBy('createdDate', descending: true)
.snapshots();
return StreamBuilder<QuerySnapshot>(
stream: stream,
builder: (context, snapshot) {
final messages = snapshot.data!.docs;
final message = messages.first.data() as dynamic;
return Text(
message['content'],
maxLines: 1,
overflow: TextOverflow.ellipsis,
);
});
Chat Room Model
String roomId;
String roomName;
DateTime createDate;
bool isDeleted;
DateTime lastestMsg;
List<String> members;
ChatRoom({
required this.roomId,
required this.roomName,
required this.createDate,
required this.isDeleted,
required this.lastestMsg,
required this.members,
});
factory ChatRoom.fromMap(Map<String, dynamic> map) {
return ChatRoom(
roomId: map['roomId'] as String,
roomName: map['roomName'] as String,
createDate: (map['createDate'] as Timestamp).toDate(),
isDeleted: map['isDeleted'] as bool,
lastestMsg: (map['lastestMsg'] as Timestamp).toDate(),
members: List<String>.from(
(map['members'] as List<dynamic>),
),
);
}
String toJson() => json.encode(toMap());
factory ChatRoom.fromJson(String source) =>
ChatRoom.fromMap(json.decode(source) as Map<String, dynamic>);
Message Model
String senderId;
String content;
DateTime createdDate;
List<String> seenBy;
bool isDeleted;
FreeLanceMessage({
required this.senderId,
required this.content,
required this.createdDate,
required this.seenBy,
required this.isDeleted,
});
factory FreeLanceMessage.fromMap(Map<String, dynamic> map) {
return FreeLanceMessage(
senderId: map['senderId'] as String,
content: map['content'] as String,
createdDate: (map['createdDate'] as Timestamp).toDate(),
seenBy: List<String>.from(
(map['seenBy'] as List<dynamic>),
),
isDeleted: map['isDeleted'] as bool,
);
}
String toJson() => json.encode(toMap());
factory FreeLanceMessage.fromJson(String source) =>
FreeLanceMessage.fromMap(json.decode(source) as Map<String, dynamic>);
Error When the Chat list screen gets mounted to the tree, it only appears for few milliseconds, when I add a new chat, the chat latest message doesn't show an error after this
I use random string so don't mind the title and the msg
Edit: I can use streambuilder and check for connection state but the screen blinks for any data change and I don't want that
so my question is, is this the right way to do this? is there another way? if so, how can I improve this

How to assign value to variable from future before screen built?

In my application user can have multiple home and multiple rooms for each home. On top of my application I have dropdown box which im trying to set default value to selectedHome by user. Below that dropdown box I am showing the rooms in the home selected by user. In firebase I have rooms collection under each home. I'm getting the selected home data from firebase too. Also to show the rooms in selected home i need to query by home name. I have two FutureBuilder as you can see code below. One of them to get the selectedHome data from firebase and other for the getting the rooms in that home from firebase. As I said before to get the rooms in selected home I need to query by name of the home so I have a parameter which is the value of dropdownbox. In my code the problem is getting the rooms part is working before I get the selectedHome data from firebase and assign it to dropdown value. In this case I'm getting "Null check operator used on a null value".
Basicly the question is how can i assign value from future to variable before screen gets build.
Here you can see the code for getting selected home data from firebase;
Future<String> selectedHome() async {
return await database.selectedHome();
}
Future<String> selectedHome() async {
DocumentSnapshot docS =
await firestore.collection("users").doc(auth.currentUser()).get();
String selectedHome = (docS.data() as Map)["selectedHome"];
return selectedHome;
}
Here you can see the code for getting room data based on selectedHome from firebase;
Future<List<Map>> deviceAndRoomInfo() async {
return database.numberOfRooms(_dropdownValue!);
}
Future<List<Map>> numberOfRooms(String selectedHome) async {
List<Map> prodsList = [];
final snapshot = await firestore
.collection("users")
.doc(auth.currentUser())
.collection("homes")
.doc(selectedHome)
.collection("rooms")
.get();
List listOfRooms = snapshot.docs;
for (int a = 1; a <= listOfRooms.length; a++) {
var productsInRoom = await firestore
.collection("users")
.doc(auth.currentUser())
.collection("homes")
.doc(selectedHome)
.collection("rooms")
.doc(listOfRooms[a - 1]["roomName"])
.collection("products")
.get();
List prodList = productsInRoom.docs
.map((e) => DeviceModel.fromMap(e.data()))
.toList();
Map qq = {
"roomName": listOfRooms[a - 1]["roomName"],
"deviceInfo": prodList
};
prodsList.add(qq);
}
return prodsList;
}
Here you can see the code for screen contains 2 future builder that i told;
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shelly_ess_production/constants.dart';
import 'package:shelly_ess_production/helper_widgets/loading_widget.dart';
import 'package:shelly_ess_production/screens/home_screen/components/circle_room_data.dart';
import 'package:shelly_ess_production/screens/home_screen/components/device_in_room_card.dart';
import 'package:shelly_ess_production/screens/home_screen/provider/home_screen_provider.dart';
import 'package:shelly_ess_production/screens/models/device_model.dart';
import 'package:shelly_ess_production/size_config.dart';
class Body extends StatefulWidget {
const Body({Key? key}) : super(key: key);
#override
State<Body> createState() => _BodyState();
}
class _BodyState extends State<Body> {
#override
Widget build(BuildContext context) {
var providerHelper =
Provider.of<HomeScreenProvider>(context, listen: false);
return SafeArea(
child: Padding(
padding:
EdgeInsets.symmetric(horizontal: getProportionateScreenWidth(0.07)),
child: SingleChildScrollView(
child: Column(
children: [
SizedBox(
height: getProportionateScreenHeight(0.02),
),
Consumer<HomeScreenProvider>(builder: (context, data, child) {
return FutureBuilder<List<String>>(
future: data.getHomesAndSelected(),
builder: (context, snapshot) {
if (snapshot.hasData) {
data.setDropDownValue = snapshot.data![0];
return DropdownButtonHideUnderline(
child: DropdownButton(
iconEnabledColor: kPrimaryColor,
iconDisabledColor: kPrimaryColor,
style: TextStyle(
color: kPrimaryColor,
fontSize: getProportionateScreenHeight(0.05)),
menuMaxHeight: getProportionateScreenHeight(0.4),
borderRadius: BorderRadius.circular(15),
key: UniqueKey(),
value: data.dropdownValue,
isExpanded: true,
icon: const Icon(Icons.arrow_downward),
onChanged: (String? newValue) async {
data.setDropDownValue = newValue;
await data.changeSelectedHome();
},
items: snapshot.data!
.map<DropdownMenuItem<String>>((String value) {
return DropdownMenuItem<String>(
alignment: Alignment.center,
value: value,
child: Text(value),
);
}).toList(),
),
);
} else {
return Transform.scale(
scale: 0.5,
child: const Center(
child: CircularProgressIndicator(),
),
);
}
});
}),
SizedBox(
height: getProportionateScreenHeight(0.02),
),
SizedBox(
height: getProportionateScreenHeight(0.14),
child: ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
itemCount: 5,
itemBuilder: (context, index) {
return CircleRoomData(
title: "Oda Sayısı",
icon: Icons.meeting_room,
content: "8",
);
}),
),
Consumer<HomeScreenProvider>(builder: (context, data, snapshot) {
return FutureBuilder<List<Map>>(
future: data.deviceAndRoomInfo(data.dropdownValue!),
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
physics: const NeverScrollableScrollPhysics(),
itemCount: snapshot.data!.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return Column(
children: [
Divider(
thickness:
getProportionateScreenHeight(0.002),
),
Text(
snapshot.data![index]["roomName"],
style: TextStyle(
fontWeight: FontWeight.bold,
color: kSecondaryColor,
fontSize:
getProportionateScreenHeight(0.03)),
),
SizedBox(
height: getProportionateScreenHeight(0.01),
),
Text(
"${(snapshot.data![index]["deviceInfo"] as List).length.toString()} Cihaz",
style:
const TextStyle(color: kSecondaryColor),
),
SizedBox(
height: getProportionateScreenHeight(0.02),
),
GridView.builder(
shrinkWrap: true,
physics:
const NeverScrollableScrollPhysics(),
itemCount: (snapshot.data![index]
["deviceInfo"] as List)
.length,
gridDelegate:
const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
),
itemBuilder: (context, indexx) {
print(index);
return DeviceInRoom(
icon: Icons.light,
productName: ((snapshot.data![index]
["deviceInfo"]
as List)[indexx] as DeviceModel)
.deviceName,
);
})
],
);
});
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
});
}
)
],
)),
),
);
}
}
Am not certain where your error is coming from, but from what I see it maybe as a result of one of your functions returning null and a rendering of your content happens before the data is received.
You could try one of these:
You could declare the return type of your feature as being nullable for example you are expecting a value of type int:
Future<int?> xyz(){
......
return .....;
}
Now because your return type is nullable you wont have an issues as long as the receiving variable is also nullable.
Alternatively:
Future<int?> xyz(){
......
return ..... ?? 10 /*some default value*/;
}
because you know you result could be null you could also provide an optional default value incase your Future call returns a null value.

Checkbox with many options

I created two checkboxes but after clicking on one of them both are marked, as in the picture below, could someone help me solve this problem?
only one can be marked,
my code:
class _LanguageSelectorState extends State<LanguageSelector> {
static final List<String> languagesList = application.supportedLanguages;
static final List<String> languageCodesList =
application.supportedLanguagesCodes;
final Map<dynamic, dynamic> languagesMap = {
languagesList[0]: languageCodesList[0],
languagesList[1]: languageCodesList[1],
};
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
backgroundColor: Colors.white,
iconTheme: IconThemeData(color: Colors.black),
title: Text(AppTranslations.of(context).text("settings_language"), style: TextStyle(color: Colors.black, letterSpacing: 1)),
elevation: 0.0,
centerTitle: true,
bottom: PreferredSize(child: Container(color: Colors.black, height: 0.1), preferredSize: Size.fromHeight(0.1),),
),
body: _buildLanguagesList()
);
}
String selectedLanguage = '';
_buildLanguagesList() {
return ListView.builder(
itemCount: languagesList.length,
itemBuilder: (context, index) {
return _buildLanguageItem(languagesList[index]);
},
);
}
bool _value = false;
_buildLanguageItem(String language) {
return CheckboxListTile(
title: Text(language),
value: _value,
onChanged: (value) {
setState(() {
_value = value;
application.onLocaleChanged(Locale(languagesMap[language]));
});
},
controlAffinity: ListTileControlAffinity.trailing,
);
}
}
thanks for any help :)
////////////////////////////////////////////////////////////////////
Take a look at this example.. Hope that will answer your question how to use checkboxes in listView
List<Map<String, dynamic>> languagesList = [
{'value': false},
{'value': false}
];
ListView.builder(
itemCount: languagesList.length,
itemBuilder: (context, index) {
return CheckboxListTile(
title: Text(languagesList[index]['value'].toString()),
value: languagesList[index]['value'],
onChanged: (value) {
setState(() {
languagesList[index]['value'] = value;
});
},
controlAffinity: ListTileControlAffinity.trailing,
);
}),
The reason your approach didn't work was because you have assigned one variable to all your checkboxes so no wander your checkboxes were updated together
Because all the widgets created by the ListView has the same value _value, if one of the widget gets checked, the value for all of the widgets change as the all depend on the same variable.
Here is a demonstration of how you can do it. it may contain errors.
import 'package:flutter/material.dart';
class LanguageItem extends StatefulWidget {
Key key;
bool isSelected = false;
YOURCLASS application;
String language;
LanguageItem({#required language, #required this.application, this.key
}):super(key:key);
#override
_LanguageItemState createState() => _LanguageItemState();
}
class _LanguageItemState extends State<LanguageItem> {
#override
Widget build(BuildContext context) {
return CheckboxListTile(
title: Text(widget.language),
value: widget.isSelected,
onChanged: (value) {
setState(() {
widget.isSelected = value;
widget.application.onLocaleChanged(Locale(languagesMap[language]));
});
},
controlAffinity: ListTileControlAffinity.trailing,
);
}
}

Categories

Resources