I try to make horizontal scrollable list inside Sliver List (CustomScrollview - SliverList)
This is my Code:
import 'package:flutter/material.dart';
class DetailScreen extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
DetailAppBar(),
SliverPadding(
padding: EdgeInsets.all(16.0),
sliver: SliverList(
delegate: SliverChildListDelegate(
[
Card(child: Text('data'),),
Card(child: Text('data'),),
Card(child: Text('data'),),
Card(child: Text('data'),),
// Scrollable horizontal widget here
],
),
),
),
],
),
bottomNavigationBar: NavigationButton());
}
}
Can you give me example or solution to this case? i really need some help.
Use a ListView inside of a SliverToBoxAdapter.
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverPadding(
padding: EdgeInsets.all(16.0),
sliver: SliverList(
delegate: SliverChildListDelegate(
[
Card(
child: Text('data'),
),
Card(
child: Text('data'),
),
Card(
child: Text('data'),
),
Card(
child: Text('data'),
),
],
),
),
),
SliverToBoxAdapter(
child: Container(
height: 100.0,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: 10,
itemBuilder: (context, index) {
return Container(
width: 100.0,
child: Card(
child: Text('data'),
),
);
},
),
),
),
],
),
);
}
the other solution doesn't work for me as it gives error when I use a ListView
here is a class I wrote called HorizontalSliverList which does the job nice and easy
here is the class you need to copy:
class HorizontalSliverList extends StatelessWidget {
final List<Widget> children;
final EdgeInsets listPadding;
final Widget divider;
const HorizontalSliverList({
Key key,
#required this.children,
this.listPadding = const EdgeInsets.all(8),
this.divider,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return SliverToBoxAdapter(
child: SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: Padding(
padding: listPadding,
child: Row(children: [
for (var i = 0; i < children.length; i++) ...[
children[i],
if (i != children.length - 1) addDivider(),
],
]),
),
),
);
}
Widget addDivider() => divider ?? Padding(padding: const EdgeInsets.symmetric(horizontal: 8));
}
Related
im new to flutter and i wanted to know how can i retrieve a user data from firebase to my profile page?
my firebase data contain a name, email, blood type, and a date of birth. and i would like to retrieve these data to my app's profile page.
this is my profile page code
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:line_awesome_flutter/line_awesome_flutter.dart';
import '../Reminder/ui/theme.dart';
class ProfilePage extends StatefulWidget {
const ProfilePage({super.key});
#override
State<ProfilePage> createState() => _ProfilePageState();
}
class _ProfilePageState extends State<ProfilePage> {
final user = FirebaseAuth.instance.currentUser!;
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
//leading: IconButton(onPressed: (){}, icon: const Icon(Icons.arrow_back_ios_new),),
centerTitle: true,
title: Text(
'Profile',
style: headingStyle,
),
backgroundColor: Get.isDarkMode ? Colors.grey[700] : Colors.white,
),
body: SingleChildScrollView(
child: Container(
padding: const EdgeInsets.all(10),
child: Column(
children: [
SizedBox(
width: 120,
height: 120,
child: Image(image: AssetImage("images/profile.png")),
),
const SizedBox(height: 50),
Form(
child: Column(
children: [
TextFormField(
decoration: InputDecoration(
prefixIconColor: Get.isDarkMode?Colors.black:Colors.white,
focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(100), borderSide: BorderSide(color: Get.isDarkMode?Colors.white:Colors.black,)),
labelText: "Email",
prefixIcon: Icon(LineAwesomeIcons.envelope_1, color: Get.isDarkMode?Colors.white:Colors.black),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(100))),
),
SizedBox(height: 10),
TextFormField(
decoration: InputDecoration(
prefixIconColor: Get.isDarkMode?Colors.black:Colors.white,
focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(100), borderSide: BorderSide(color: Get.isDarkMode?Colors.white:Colors.black,)),
labelText: "Full Name",
prefixIcon: Icon(LineAwesomeIcons.user, color: Get.isDarkMode?Colors.white:Colors.black),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(100))),
),
SizedBox(height: 10),
TextFormField(
decoration: InputDecoration(
prefixIconColor: Get.isDarkMode?Colors.black:Colors.white,
focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(100), borderSide: BorderSide(color: Get.isDarkMode?Colors.white:Colors.black,)),
labelText: "Date of Birth",
prefixIcon: Icon(LineAwesomeIcons.baby_carriage, color: Get.isDarkMode?Colors.white:Colors.black),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(100))),
),
SizedBox(height: 10),
TextFormField(
decoration: InputDecoration(
prefixIconColor: Get.isDarkMode?Colors.black:Colors.white,
focusedBorder: OutlineInputBorder(borderRadius: BorderRadius.circular(100), borderSide: BorderSide(color: Get.isDarkMode?Colors.white:Colors.black,)),
labelText: "Blood Type",
prefixIcon: Icon(Icons.bloodtype, color: Get.isDarkMode?Colors.white:Colors.black),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(100))),
),
SizedBox(height: 15,),
SizedBox(
width: 100,
child: MaterialButton(
onPressed: () {
FirebaseAuth.instance.signOut();
},
color: Colors.redAccent,
child: Text('SIGN OUT'),
),
),
],
),
)
],
),
),
),
);
}
}
Use either StreamBuilder or FutureBuilder and get the data from firebase and display it accordingly
1. StreamBuilder
When you want to listen to changes constantly, and want the data to get updated without hot reload/restart
2. FutureBuilder
When you want to get the document only once and have no requirement of listening constantly to the change of the document.
Using StreamBuilder
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: StreamBuilder<DocumentSnapshot<Map<String, dynamic>>>(
stream: FirebaseFirestore
.instance
.collection('users')
.doc(FirebaseAuth.instance.currentUser!.uid) // 👈 Your document id which is equal to currentuser
.snapshots(),
builder:
(BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return const Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return const Text("Loading");
}
Map<String, dynamic> data =
snapshot.data!.data()! as Map<String, dynamic>;
return Text(data['fullName']); // 👈 your valid data here
},
),
),
);
}
Using FutureBuilder
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FutureBuilder<DocumentSnapshot<Map<String, dynamic>>>(
future: FirebaseFirestore.instance
.collection('users')
.doc(FirebaseAuth.instance.currentUser!.uid) // 👈 Your document id which is equal to currentuser
.get(),
builder: (_, snapshot) {
if (snapshot.hasError) return Text('Error = ${snapshot.error}');
if (snapshot.connectionState == ConnectionState.waiting) {
return const Text("Loading");
}
Map<String, dynamic> data = snapshot.data!.data()!;
return Text(data['fullName']); //👈 Your valid data here
},
)),
);
}
You can use stram builder to retrieve data from the firebase and display it to the user on real time. It may have some issues with styling, since I wrote it without any IDE, but I hope you'll get the idea how to get your data from stream builder.
Example:
class ProfilePage extends StatefulWidget {
const ProfilePage({super.key});
#override
State<ProfilePage> createState() => _ProfilePageState();
}
class _ProfilePageState extends State<ProfilePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children:[
StreamBuilder(
stream: FirebaseFirestore.instance
.collection('your_collection')
.snapshots(),
builder: (context,
AsyncSnapshot<QuerySnapshot> snapshot) {
if (!snapshot.hasData) {
return Center(
child: SizedBox(
height: 50,
width: 50,
child: CircularProgressIndicator(
color: Style.blueColorDark,
backgroundColor: Style.olive,
),
),
);
}else{
return ListView(
shrinkWrap: true,
children: snapshot.data!.docs.map((document) {
return Padding(
padding: const EdgeInsets.symmetric(
horizontal: 16),
child: Card(
color: const Color.fromRGBO(
255, 255, 255, 1)
.withOpacity(0.6),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(15),
),
child: Column(
children: <Widget>[
Text(data['name']),
Text(data['email']),
Text(data['bloodType']),
Text(data['dob']),
],
),
),
);
}).toList(),
);
}
}
)
]
)
}
}
I am putting up 3 .dart files which are required for the app.
StaffEvent.dart
import 'package:flutter/material.dart';
import 'package:flutter_new_app/addevent_screen.dart';
import 'package:flutter_new_app/services/crud.dart';
class StaffEvent extends StatefulWidget {
#override
_StaffEventState createState() => _StaffEventState();
}
class _StaffEventState extends State<StaffEvent> {
CrudMethods crudMethods = new CrudMethods();
QuerySnapshot eventSnapshot;
Stream eventStream;
// ignore: non_constant_identifier_names
Widget EventList() {
return Container(
child: eventStream != null
? Column(
children: [
StreamBuilder(
stream: eventStream,
builder: (context, snapshot) {
return ListView.builder(
padding: EdgeInsets.symmetric(horizontal: 16),
itemCount: eventSnapshot.docs.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return EventTile(
title: eventSnapshot.docs[index].data()['title'],
desc: eventSnapshot.docs[index].data()['desc'],
date: eventSnapshot.docs[index].data()['date'],
);
},
);
},
),
],
)
: Container(
alignment: Alignment.center,
child: CircularProgressIndicator(),
),
);
}
#override
void initState() {
setState(() {
Stream result;
eventStream = result;
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFFffffff),
appBar: AppBar(
actions: [
FloatingActionButton(
backgroundColor: Colors.green,
child: Icon(Icons.add),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => AddEvent()),
);
},
)
],
backgroundColor: Color(0xFFebd8b7),
title: Text(
'Events',
style: TextStyle(color: Colors.black),
),
),
);
}
}
// ignore: must_be_immutable
class EventTile extends StatelessWidget {
String title, desc, date;
EventTile({#required this.title, #required this.desc, #required this.date});
#override
Widget build(BuildContext context) {
return Column(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(6),
child: SizedBox(
width: 500,
height: 80,
child: Container(
color: Color(0xFFeaffd0),
child: Column(
children: [
Text(
title,
textAlign: TextAlign.center,
style: TextStyle(fontSize: 25, fontWeight: FontWeight.w500),
),
Text(
desc,
style: TextStyle(fontSize: 17, fontWeight: FontWeight.w400),
),
Text(
date,
style: TextStyle(fontSize: 17, fontWeight: FontWeight.w400),
)
],
),
),
),
),
],
);
}
}
Crud.dart
import 'package:cloud_firestore/cloud_firestore.dart';
class CrudMethods {
Future<void> addData(eventData) async {
FirebaseFirestore.instance
.collection("events")
.add(eventData)
.catchError((e) {
print(e);
});
}
getData() async {
return await FirebaseFirestore.instance.collection("events").get();
}
}
Addevent.dart
import 'package:flutter_new_app/services/crud.dart';
class AddEvent extends StatefulWidget {
#override
_AddEventState createState() => _AddEventState();
}
class _AddEventState extends State<AddEvent> {
String title, desc, date;
CrudMethods crudMethods = new CrudMethods();
uploadEvent() async {
Map<String, String> eventMap = {"title": title, "desc": desc, "date": date};
crudMethods.addData(eventMap).then((result) {
Navigator.pop(context);
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFFffffff),
appBar: AppBar(
backgroundColor: Color(0xFFf38181),
title: Text(
'Add Event',
style: TextStyle(color: Colors.black),
),
actions: <Widget>[
GestureDetector(
onTap: () {
uploadEvent();
},
child: Container(
padding: EdgeInsets.symmetric(horizontal: 16),
child: Icon(Icons.file_upload)),
)
],
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
decoration: InputDecoration(hintText: "Event Name"),
onChanged: (val) {
title = val;
},
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
decoration: InputDecoration(hintText: "Description"),
onChanged: (val) {
desc = val;
},
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
decoration: InputDecoration(hintText: "Date"),
onChanged: (val) {
date = val;
},
),
)
],
));
}
}
So here basically, the user has to enter some details for an event and when clicking the upload button it should be visible as a list in the Staffevent page . That is the problem. Nothung is showing in the Staffevent page. It is blank.
The data is being stored in the firebase database but when i am using snapshot and calling it back it is not showing in my flutter application.
Your stream is empty:
Stream result;
eventStream = result;
Firebase Firestore get() method returns a Future<DocumentSnapshot>:
Future<DocumentSnapshot> getData() async {
return await FirebaseFirestore.instance.collection("events").get();
}
If you need a stream you use snapshots() method which returns a Stream:
Stream collectionStream = FirebaseFirestore.instance.collection("events").snapshots();
Please refer to official documentation to get familiar with Firebase API.
I have a column which has two widgets wherein there's a list view of 3 different containers which is scrollable horizontally and there an inkwell.
What Inkwell is doing is that it is having a click functionality wherein if I click on that inkwell it should redirect me to one of the containers in the list view and also it should be able to scroll in the horizontal axis.
But what I have coded down is it is navigating me to the desired screen but the thing is that the app bar is getting vanished and the scrolling ability is also not there and also few yellow line errors were also coming.
Code Snippet:
import 'package:book/shared/colors.dart';
import 'package:flutter/material.dart';
class ListExample extends StatefulWidget {
#override
_ListExampleState createState() => _ListExampleState();
}
class _ListExampleState extends State<ListExample> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.blue,
),
body: Column(
children: [
Expanded(
child: ListView(
scrollDirection: Axis.horizontal,
children: [
Container(
height: 800,
width: 1200,
child: Center(
child: Text('Screen 1'), // 1st Page.
),
),
Screen2(), // 2nd Page
Container(
height: 800,
width: 1200,
child: Center(
child: Text('Screen 3'), // 3rd Page.
),
),
],
),
),
Expanded(
child: Row(
children: [
Container(
height: 60,
width: 800,
decoration: BoxDecoration(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
),
color: AppColors.getLightBlue(),
),
),
InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Screen2(), /// Using the navigator is not solving the problem
),
);
},
child: Text(
'Screen 2'), // The name should change as we navigate throgh differnt screen
),
],
),
)
],
),
);
}
}
class Screen2 extends StatelessWidget {
const Screen2({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Container(
height: 800,
width: 1200,
child: Center(
child: Text('Screen 2'), // 2nd Page.
),
);
}
}
Please help me solve the error.
Tried the few packages such as scrollable_position_list, etc but nothing helped me with this.
Background: I'm writing an app in which you can store the plus points and fives of a class.
I do this with Flutter and Firebase. My Firestore database collection is called 'mates' and it has several documents, with a unique, auto-ID. Every document has three fields: a name(string), points(number), fives(number).
I have made this far with the help of this tutorial: https://www.youtube.com/watch?v=DqJ_KjFzL9I&t=591s
I want to modify the GUI a bit, in each listtile I display the name, button for decrementing points, the value of points, button for incrementing points, button for decrementing fives, value of fives, button for incrementing fives and a button for setting the value of fives to zero.
My question would be, that how can I refer to the fields(points, fives) of the database when changing their values?
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
Widget _buildListItem(BuildContext context, DocumentSnapshot document){
return ListTile(
title: Row(
children: [
Expanded(
child: Text(
document["Name"],
style: Theme.of(context).textTheme.headline,
)
),
Container(
decoration: const BoxDecoration(
color: Color(0xffddddff)
),
padding: const EdgeInsets.all(10.0),
child: Text(
document['Points'].toString(),
style: Theme.of(context).textTheme.display1,
),
),
Container(
child: Row(
children: <Widget>[
IconButton(
icon: Icon(Icons.keyboard_arrow_left),
iconSize: 30,
onPressed: (){
setState(() {
if(points!=0) { //I mean here
points--; //I mean here
}
});
}
),
Text(
"$points", //I mean here
style: TextStyle(
fontSize: 30
),
),
IconButton(
icon: Icon(Icons.keyboard_arrow_right),
iconSize: 30,
onPressed: (){
setState(() {
points++; //I mean here
if(points==10){ //I mean here
points=0; //I mean here
fives++; //I mean here
}
});
}
),
Text(
"$fives", //I mean here
style: TextStyle(
fontSize: 30
),
),
IconButton(
icon: Icon(Icons.check_circle),
iconSize: 30,
onPressed: (){
setState(() {
fives=0; //I mean here
});
}
),
]
)
),
],
),
);
}
#override
Widget build(BuildContext context) {
return Center(
child: Scaffold(
appBar: AppBar(
title: Text("Punkte++"),
centerTitle: true,
),
body: StreamBuilder(
stream: Firestore.instance.collection("mates").snapshots(),
builder: (context, snapshot) {
if(!snapshot.hasData) return const Text("Loading...");
return ListView.builder(
itemExtent: 80.0,
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) =>
_buildListItem(context, snapshot.data.documents[index]),
);
}
),
)
);
}
}
I am trying to add some city list to a dialog with checkbox so that i need to implement multiple click on items. what I am trying to do is given below.
onPressed from button calls Rest Service and on success result I just show a dialog
void showCityDialog(BuildContext context) {
SimpleDialog dialog = new SimpleDialog(
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
new Text(
"CITIES",
style: TextStyle(fontSize: 18.0, color: Colors.black),
textAlign: TextAlign.center,
),
new RaisedButton(
onPressed: () {print("clicked");},
color: Color(0xFFfab82b),
child: new Text(
"Done",
style: TextStyle(color: Colors.white),
),)],),
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Container(
constraints: BoxConstraints(maxHeight: 500.0),
child: ListView.builder(
scrollDirection: Axis.vertical,
itemCount: cityData.length,
itemBuilder: (context, position) {
return new CheckboxListTile(
value: checkboxValueCity,
onChanged: (bool value) {
setState(() {
checkboxValueCity = value;
});
},
activeColor: Color(0xFFfab82b),
dense: true,
title: Text(
cityData[position].city_name,
style: TextStyle(fontSize: 16.0, color: Colors.black),
),);},),),],)],);
showDialog(
context: context,
builder: (BuildContext context) {
return dialog;
});
}
checkboxValueCity is a boolean variable in class , on click of chekboxListItem i need to update checkbox value as checked and uncheced. At the same time need to add/remove that item to a list which is also inside that class.
But in my code checkbox is not refershing on every click but when i close that box and open it again checkbox is checked. then how can i get multiple click from tile and how can i return list from dialog?
Your dialog needs to be a StatefulWidget (Flutter Github issue). The member variable that tracks selection state needs to be in the dialog class. You can use a callback to update a member variable in your parent class with the List of selected cities. There also seem to be some issues using a ListView.builder inside of a SimpleDialog or AlertDialog (search the Flutter Github for issues) so I used a plain Dialog.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Checkbox Dialog Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Checkbox Dialog Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool checkboxValueCity = false;
List<String> allCities = ['Alpha', 'Beta', 'Gamma'];
List<String> selectedCities = [];
#override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
showDialog(
context: context,
builder: (context) {
return _MyDialog(
cities: allCities,
selectedCities: selectedCities,
onSelectedCitiesListChanged: (cities) {
selectedCities = cities;
print(selectedCities);
});
});
}),
);
}
}
class _MyDialog extends StatefulWidget {
_MyDialog({
this.cities,
this.selectedCities,
this.onSelectedCitiesListChanged,
});
final List<String> cities;
final List<String> selectedCities;
final ValueChanged<List<String>> onSelectedCitiesListChanged;
#override
_MyDialogState createState() => _MyDialogState();
}
class _MyDialogState extends State<_MyDialog> {
List<String> _tempSelectedCities = [];
#override
void initState() {
_tempSelectedCities = widget.selectedCities;
super.initState();
}
#override
Widget build(BuildContext context) {
return Dialog(
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'CITIES',
style: TextStyle(fontSize: 18.0, color: Colors.black),
textAlign: TextAlign.center,
),
RaisedButton(
onPressed: () {
Navigator.pop(context);
},
color: Color(0xFFfab82b),
child: Text(
'Done',
style: TextStyle(color: Colors.white),
),
),
],
),
Expanded(
child: ListView.builder(
itemCount: widget.cities.length,
itemBuilder: (BuildContext context, int index) {
final cityName = widget.cities[index];
return Container(
child: CheckboxListTile(
title: Text(cityName),
value: _tempSelectedCities.contains(cityName),
onChanged: (bool value) {
if (value) {
if (!_tempSelectedCities.contains(cityName)) {
setState(() {
_tempSelectedCities.add(cityName);
});
}
} else {
if (_tempSelectedCities.contains(cityName)) {
setState(() {
_tempSelectedCities.removeWhere(
(String city) => city == cityName);
});
}
}
widget
.onSelectedCitiesListChanged(_tempSelectedCities);
}),
);
}),
),
],
),
);
}
}
Use StatefulBuilder to update Widgets only inside Dialog. StatefulBuilder is best for update sebsection of the widget tree where
state is needed.
simple code snippet
void _showDialog() {
showDialog(
context: context,
builder: (context) {
return StatefulBuilder( // StatefulBuilder
builder: (context, setState) {
return AlertDialog(
actions: <Widget>[
Container(
width: 400,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text(
"Student Attendence",
style: TextStyle(fontSize: 20),
),
SizedBox(
height: 5,
),
Container(
height: 2,
color: Colors.black,
),
SizedBox(
height: 15,
),
CheckboxListTile(
value: user1,
title: Text("user1"),
onChanged: (value){
setState(() {
user1=value;
});
},
),
Divider(
height: 10,
),
CheckboxListTile(
value: user2,
title: Text("user2"),
onChanged: (value){
setState(() {
user2=value;
});
},
),
Divider(
height: 10,
),
CheckboxListTile(
value: user3,
title: Text("user3"),
onChanged: (value){
setState(() {
user3=value;
});
},
),
Divider(
height: 10,
),
CheckboxListTile(
value: user4,
title: Text("user4"),
onChanged: (value){
setState(() {
user4=value;
});
},
),
Divider(
height: 10,
),
SizedBox(
height: 5,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Material(
elevation: 5.0,
color: Colors.blue[900],
child: MaterialButton(
padding: EdgeInsets.fromLTRB(
10.0, 5.0, 10.0, 5.0),
onPressed: () {},
child: Text("Save",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 15,
)),
),
),
Material(
elevation: 5.0,
color: Colors.blue[900],
child: MaterialButton(
padding: EdgeInsets.fromLTRB(
10.0, 5.0, 10.0, 5.0),
onPressed: () {
setState(() {
Navigator.of(context).pop();
});
},
child: Text("Cancel",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 15,
)),
),
),
Material(
elevation: 5.0,
color: Colors.blue[900],
child: MaterialButton(
padding: EdgeInsets.fromLTRB(
10.0, 5.0, 10.0, 5.0),
onPressed: () {},
child: Text("Select All",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 15,
)),
),
),
],
)
],
))
],
);
},
);
},
);
}
example
Although Albert's answer works, you need not go thru all that. Simply wrap the content: with a StatefulBuilder, voila!
https://api.flutter.dev/flutter/widgets/StatefulBuilder-class.html.
Note: It is important where you declare the variable(s) you want to change.
I modified your code a bit, I want when users check the list, the list won't be updated to the main view, but they will when users click the "Update" button.
But some how, it doesn't work. Can you please check ?
Thank you very much
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Checkbox Dialog Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Checkbox Dialog Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool checkboxValueCity = false;
List<String> allCities = ['Alpha', 'Beta', 'Gamma'];
List<String> selectedCities = [];
List<String> selectedCitiesTemp = [];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("App Bar"),
),
body: Center(
child: Column(
children: <Widget>[
_list(),
RaisedButton(
child: Text("Update From TMP List"),
onPressed: () {
setState(() {
selectedCities = selectedCitiesTemp;
});
},
)
],
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return _MyDialog(
cities: allCities,
selectedCities: selectedCities,
onSelectedCitiesListChanged: (cities) {
setState(() {
selectedCitiesTemp = cities;
});
},
);
});
}),
);
}
Widget _list() {
List<Widget> list = [];
for(String item in selectedCities) {
list.add(ListTile(
title: Text(item),
));
}
return Column(
children: list
);
}
}
class _MyDialog extends StatefulWidget {
_MyDialog({
this.cities,
this.selectedCities,
this.onSelectedCitiesListChanged,
});
final List<String> cities;
final List<String> selectedCities;
final ValueChanged<List<String>> onSelectedCitiesListChanged;
#override
_MyDialogState createState() => _MyDialogState();
}
class _MyDialogState extends State<_MyDialog> {
List<String> _tempSelectedCities = [];
#override
void initState() {
_tempSelectedCities = widget.selectedCities;
super.initState();
}
#override
Widget build(BuildContext context) {
return Dialog(
child: Column(
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(
'CITIES',
style: TextStyle(fontSize: 18.0, color: Colors.black),
textAlign: TextAlign.center,
),
],
),
Expanded(
child: ListView.builder(
itemCount: widget.cities.length,
itemBuilder: (BuildContext context, int index) {
final cityName = widget.cities[index];
return Container(
child: CheckboxListTile(
title: Text(cityName),
value: _tempSelectedCities.contains(cityName),
onChanged: (bool value) {
if (value) {
if (!_tempSelectedCities.contains(cityName)) {
setState(() {
_tempSelectedCities.add(cityName);
});
}
} else {
if (_tempSelectedCities.contains(cityName)) {
setState(() {
_tempSelectedCities.removeWhere(
(String city) => city == cityName);
});
}
}
widget.onSelectedCitiesListChanged(_tempSelectedCities);
}),
);
}),
),
],
),
);
}
}