I have a showModalBottomSheetwith Listview with 4 checkbox data,i am facing a problem.
1:Whenever i press on each checkbox it's not updating,then if i close the showModalBottomSheet then open again it show the data selected earlier,it's not updating real time.
there is no problem with getting data from the API
Initialized data
var ids;
List<SearchMenuModel> menu_model = [];
List<bool> inputs = new List<bool>();
#override
void initState() {
// TODO: implement initState
setState(() {
for(int i=0;i<menu_model.length;i++){
inputs.add(true);
}
});
void ItemChange(bool val,int index){
setState(() {
inputs[index] = val;
});
}
Showmodalbottomsheet with Listview with checkbox
void displayBottomSheet(BuildContext context) {
showModalBottomSheet(
context: context,
builder: (ctx) {
return Container(
height: MediaQuery
.of(context)
.size
.height * 0.6,
child: Column(
children: [
Container(
width: 300,
height: 250,
child: new ListView.builder(
itemCount: menu_model.length,
itemBuilder: (BuildContext context, int index){
return new Container(
padding: new EdgeInsets.all(10.0),
child: new Column(
children: <Widget>[
new CheckboxListTile(
value: inputs[index],
title: new Text(menu_model[index].english),
controlAffinity:
ListTileControlAffinity.leading,
onChanged:(bool val){
ItemChange(val, index);
setState(() {
ids=menu_model[index].id;
print(ids);
});
}
)
],
),
);
}
),
),
Padding(
padding: const EdgeInsets.all(15),
child: GestureDetector(
onTap: (){
submit(ids);
},
child: Container(
height: 40,
width: 280,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5),
color: Color.fromRGBO(34, 83, 148, 1),
),
child: Center(
child: Text(
"APPLY",
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.bold),
),
),
),
),
)
],
),
);
});
}
Wrap your Container in a StatefulBuilder like this:
StatefulBuilder(
builder: (context, setState) {
return Container()....
})
and call the setState anytime you want the bottom sheet container widget to change.
Here is a link with a simple example using statefulbuilder with alertdialog.
Related
I am trying to use Getx on simple ListView but its showing error that [Get] the improper use of a GetX has been detected.
Widget getBody() {
var size = MediaQuery.of(context).size;
final controller = Get.put(PassionController());
return SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.only(left: 30, right: 30),
child: Column(
children: [
GetX<PassionController>(
builder: (_) => ListView.builder(
itemCount: controller.passionItems.length,
itemBuilder: (context, index) {
return ListTile(
title:
Text('Number: ${controller.passionItems[index]}'),
);
})),
GestureDetector(
onTap: () {
Navigator.push(
context, MaterialPageRoute(builder: (_) => MyHomePage()));
},
child: Container(
width: size.width,
height: 55,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(30), color: Colors.white
// gradient:
// LinearGradient(colors: [primary_one, primary_two])
),
child: Center(
child: Text(
"Continue",
style: TextStyle(
color: kPrimarycolor,
fontSize: 18,
fontWeight: FontWeight.w500),
),
),
),
)
],
),
),
);
}
I also try GetxBuilder but same error showing. I already wrap GetMaterial on main.dart
I am showing a showModalBottomSheet using a function. I want that as soon as it closes, value of a variable should change. I wanted to change value of two variables, but I am not able to change for even one. Please help me with this. I tried to make my own onChanged and also tried to return the value using function, but nothing happens.
This is the function, please scroll to the last of it and check out the onTap function and return.
String showChapterSelectionSheet(
BuildContext context,
List<ChapterModel> chapter_list,
String chapter_name,
final Function(String) onChapterChanged) {
String retValue = chapter_name;
showModalBottomSheet(
context: context,
backgroundColor: Colors.transparent,
elevation: 0,
isScrollControlled: true,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20), topRight: Radius.circular(20)),
),
builder: (context) {
return StatefulBuilder(
builder: (BuildContext context,
StateSetter setState /*You can rename this!*/) {
return makeDismissible(
context,
child: DraggableScrollableSheet(
initialChildSize: 0.81,
minChildSize: 0.5,
maxChildSize: 0.81,
builder: (_, controller) => Container(
padding: EdgeInsets.all(getProportionateScreenWidth(25)),
height: getProportionateScreenWidth(600),
decoration: BoxDecoration(
color: backgroundColor2,
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
child: Column(
children: [
Padding(
padding: EdgeInsets.only(
top: getProportionateScreenHeight(32),
bottom: getProportionateScreenHeight(16)),
child: Text(
AppLocalizations.of(context)!.chapters,
style: Theme.of(context)
.textTheme
.headline2!
.apply(color: Colors.white),
),
),
Expanded(
child: ListView.builder(
shrinkWrap: true,
controller: controller,
itemCount: chapter_list.length,
itemBuilder: (_, index) {
return GestureDetector(
child: Padding(
padding: EdgeInsets.only(
top: getProportionateScreenHeight(8)),
child: Card(
child: Container(
height: getProportionateScreenHeight(56),
width: getProportionateScreenWidth(341),
decoration: BoxDecoration(
border: Border.all(color: cardColor),
color: chapter_list[index].chapter_name! ==
chapter_name
? backgroundColor
: cardColor,
),
child: Padding(
padding: EdgeInsets.all(0),
child: Center(
child: Row(
children: [
Container(
width:
getProportionateScreenWidth(
32),
child: chapter_list[index]
.chapter_name! ==
chapter_name
? Icon(
Icons.check,
color: brandYellow,
)
: SizedBox()),
Text(
"Chapter ${chapter_list[index].position!}: ",
style: Theme.of(context)
.textTheme
.bodyText2!
.apply(color: brandYellow),
),
Expanded(
child: Text(
chapter_list[index]
.chapter_name!,
style: Theme.of(context)
.textTheme
.bodyText2!
.apply(
color: chapter_list[
index]
.chapter_name! ==
chapter_name
? tertiaryTextColor
: primaryTextColor)),
),
],
),
),
),
),
),
),
onTap: () {
onChapterChanged(chapter_list[index].chapter_name!);
setState(() {
retValue = chapter_list[index].chapter_name!;
});
Navigator.pop(context);
},
);
},
),
),
],
),
),
),
);
},
);
},
);
return retValue;
}
And I am accessing it here -
return InkWell(
onTap: () async {
if(dataList.isNotEmpty) {
chapterName.value = showChapterSelectionSheet(
context,dataList,chapterName.value,(val) {
setState(() {
chapterName.value = val;
print("Val is - $val");
});
}
);
}
},
child: .....
);
In the above InkWell, the print statement is working fine but value is not changing.
And I want to update and use the value here -
child: ValueListenableBuilder(
valueListenable: chapterName,
builder: (context, String val, Widget? child) {
return Text(
val,
style: TextStyle(
color: Colors.white,
fontSize: 15,
),
);
},
),
It is possible you are just missing await before await showModalBottomSheet(..).
You can follow this simplified snippet.
class BVChange extends StatefulWidget {
const BVChange({Key? key}) : super(key: key);
#override
State<BVChange> createState() => _BVChangeState();
}
class _BVChangeState extends State<BVChange> {
String var1 = "Old", var2 = "old1";
Future<String> _showDialog(String v) async {
double _sliderValue = 0.0;
await showModalBottomSheet(
context: context,
builder: (_) {
return StatefulBuilder(
builder: (context, sbSate) => Column(
children: [
Text(_sliderValue.toString()),
Slider(
value: _sliderValue,
onChanged: (sval) {
sbSate(() {
_sliderValue = sval;
});
}),
],
),
);
});
return _sliderValue.toString();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
GestureDetector(
onTap: () async {
final data = await _showDialog(var1);
setState(() {
var1 = data;
});
},
child: Text("var1 : $var1")),
GestureDetector(
onTap: () async {
final data = await _showDialog(var2);
setState(() {
var2 = data;
});
},
child: Text("var 2 : $var2"),
),
],
),
);
}
}
I'm new to Flutter/Dart developing but i'm having this issue where calling setState is not rebuilding the widget.
I'm trying to show in the UI the genres picked by the user when tapping on them as well as adding them to another list. The color of the tapped selection is supposed to change yet when reopening the modal nothing changes but the genre is actually added to another list.
Here's the code
class GenresPicker extends StatefulWidget {
#override
_GenresPickerState createState() => _GenresPickerState();
}
class _GenresPickerState extends State<GenresPicker> {
List<Genre> _selectedGenres = [];
#override
void initState() {
super.initState();
}
addGenre(genre) {
setState(() {
_selectedGenres.add(genre);
});
}
#override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
padding: EdgeInsets.all(20),
child: FutureBuilder<List<Genre>>(
future: fetchGenres(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return Container(
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"MODAL BOTTOM SHEET EXAMPLE",
style: TextStyle(
fontStyle: FontStyle.italic,
letterSpacing: 0.4,
fontWeight: FontWeight.w600),
),
SizedBox(
height: 20,
),
ElevatedButton(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (context) {
return Column(
children: <Widget>[
Text("Genres:"),
Expanded(
child: GridView.builder(
gridDelegate:
SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 100,
childAspectRatio: 4 / 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10),
itemCount: snapshot.data!.length,
itemBuilder: (BuildContext ctx, index) {
return Container(
alignment: Alignment.center,
child: GestureDetector(
onTap: () {
//_selectedGenres
// .add(snapshot.data![index]);
if (!_selectedGenres.contains(
snapshot.data![index])) {
addGenre(snapshot.data![index]);
}
},
child: Text(snapshot.data![index].name),
),
decoration: BoxDecoration(
color: _selectedGenres.contains(
snapshot.data![index])
? Colors.blue[200]
: Colors.blue[50],
borderRadius:
BorderRadius.circular(15)),
);
},
),
),
],
);
},
);
},
child: Text(
'Click Me',
style: TextStyle(
color: Colors.white,
fontWeight: FontWeight.w600,
letterSpacing: 0.6),
),
),
],
),
);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
// By default, show a loading spinner.
return Center(child: CircularProgressIndicator());
},
),
);
}
}
The commented code was a workoround that somehow worked better but not the intended result since with it when tapping and reopening the modal the selection is actually shown.
Thanks in advance.
This happens just because you use setState inside the showModalBottomSheet(Dialog).
Make sure whenever you want to refresh data inside the dialog wrap the child with StatefulBuilder and use that builder's setState to refresh the list it will work.
Check the example
import 'package:flutter/material.dart';
class BottomRefreshExample extends StatefulWidget {
#override
_BottomRefreshExampleState createState() => _BottomRefreshExampleState();
}
class _BottomRefreshExampleState extends State<BottomRefreshExample> {
List<String> _selectedListData = [];
List<String> _responseListData = ["Add1", "Add2", "Add3", "Add4", "Add5"];
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
return Container(
alignment: Alignment.center,
padding: EdgeInsets.all(20),
child: Container(
alignment: Alignment.center,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
"MODAL BOTTOM SHEET EXAMPLE",
style: TextStyle(fontStyle: FontStyle.italic, letterSpacing: 0.4, fontWeight: FontWeight.w600, fontSize: 12),
),
SizedBox(
height: 20,
),
ElevatedButton(
onPressed: () {
showModalBottomSheet(
context: context,
builder: (context) {
return StatefulBuilder(builder: (context, setNewState) {
return Column(
children: <Widget>[
Expanded(
child: GridView.builder(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 100, childAspectRatio: 4 / 2, crossAxisSpacing: 10, mainAxisSpacing: 10),
itemCount: _responseListData.length,
itemBuilder: (BuildContext ctx, index) {
return Container(
alignment: Alignment.center,
child: GestureDetector(
onTap: () {
if (!_selectedListData.contains(_responseListData[index])) {
setNewState(() {
_selectedListData.add(_responseListData[index]);
});
}
},
child: Text(_responseListData[index]),
),
decoration: BoxDecoration(
color: _selectedListData.contains(_responseListData[index]) ? Colors.blue[200] : Colors.blue[50],
borderRadius: BorderRadius.circular(15)),
);
},
),
),
],
);
});
},
);
},
child: Text(
'Open Bottom Sheet',
style: TextStyle(color: Colors.white, fontWeight: FontWeight.w600, letterSpacing: 0.6),
),
),
],
),
),
);
}
}
My Scrollview not Responding, can someone tell what I am missing in code:
Please Suggest me how to add scroll view listener I'm beginner.
import 'package:flutter/material.dart';
import 'package:share/share.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:url_launcher/url_launcher.dart';
import '../main.dart';
import 'favourite_articles.dart';
import 'coin_system.dart';
class Settings extends StatefulWidget {
#override
_SettingsState createState() => _SettingsState();
}
class _SettingsState extends State<Settings> {
bool _notification = false;
ScrollController _controller;
#override
void initState() {
super.initState();
checkNotificationSetting();
}
checkNotificationSetting() async {
final prefs = await SharedPreferences.getInstance();
final key = 'notification';
final value = prefs.getInt(key) ?? 0;
if (value == 0) {
setState(() {
_notification = false;
});
} else {
setState(() {
_notification = true;
});
}
}
saveNotificationSetting(bool val) async {
final prefs = await SharedPreferences.getInstance();
final key = 'notification';
final value = val ? 1 : 0;
prefs.setInt(key, value);
if (value == 1) {
setState(() {
_notification = true;
});
} else {
setState(() {
_notification = false;
});
}
Future.delayed(const Duration(milliseconds: 500), () {
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (BuildContext context) => MyHomePage()));
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
centerTitle: true,
title: Text(
'More',
style: TextStyle(
color: Colors.black,
fontWeight: FontWeight.bold,
fontSize: 20,
fontFamily: 'Poppins'),
),
elevation: 5,
backgroundColor: Colors.white,
actions: <Widget>[
IconButton(
icon: Icon(Icons.mail),
color: Colors.black,
tooltip: 'Song Request',
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CoinSystem(),
),
);
})
],
),
body: Container(
decoration: BoxDecoration(color: Colors.white),
child: SingleChildScrollView(
controller: _controller,
scrollDirection: Axis.vertical,
child: Column(
children: <Widget>[
Container(
alignment: Alignment.center,
padding: EdgeInsets.fromLTRB(0, 20, 0, 10),
child: Image(
image: AssetImage('assets/icon.png'),
height: 50,
),
),
Container(
alignment: Alignment.center,
padding: EdgeInsets.fromLTRB(0, 10, 0, 20),
child: Text(
"Version 2.1.0 \n ",
textAlign: TextAlign.center,
style: TextStyle(height: 1.6, color: Colors.black87),
),
),
Divider(
height: 10,
thickness: 2,
),
//ListWheelScrollView(
ListView(
//itemExtent: 75,
shrinkWrap: true,
children: <Widget>[
InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => FavouriteArticles(),
),
);
},
child: ListTile(
leading: Image.asset(
"assets/more/favourite.png",
width: 30,
),
title: Text('Favourite'),
subtitle: Text("See the saved songs"),
),
),
//Song Request Code
InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => CoinSystem(),
),
);
},
child: ListTile(
leading: Image.asset(
"assets/more/songrequest.png",
width: 30,
),
title: Text('Songs Request'),
subtitle: Text("Request your favourite songs"),
),
),
//Song Request Code End
ListTile(
leading: Image.asset(
"assets/more/notification.png",
width: 30,
),
isThreeLine: true,
title: Text('Notification'),
subtitle: Text("Change notification preference"),
trailing: Switch(
onChanged: (val) async {
await saveNotificationSetting(val);
},
value: _notification),
),
],
)
],
),
),
),
//),
);
//);
}
}
So, I have tried SingleChildScrollView, in that I have Container and Listview. But Listview doesn't response on scrolling action in landscape mode.
I have added ScrollController _controller; Do i have to create _controller class that listern the scrolling action?
In my understanding, you want to be able to get 2 scrolling. 1. using SingleChildScrollView and inside that Widget, you want to be able to scroll the bottom layer, thus you use ListView. To make it work, you have to place your ListView inside widget that has certain height. Example this implementation is:
SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: <Widget>[
SizedBox(child: Text('Upper scrollable'), height: 450),
Divider(
height: 10,
thickness: 2,
),
Container(
height: 350,
child: ListView(
shrinkWrap: true,
children: <Widget>[
Container(
color:Colors.red,
child: SizedBox(child: Text('Bottom scrollable'), height: 450),
),
],
),
)
],
),
),
If you don't want to use 2 scroll, don't use ListView inside SingleChildScrollView.
ListView cannot be wrapped with SingleChildScrollView remove it
surround ListView with Expanded Widget
try one of the two alternatives.
i need help to build a quiz app with flutter,
i use firestore for my data, and i want to add a multi choices question, so when a user tap on one choice, this one is highlighted, like this example
(i use this gif from another question, because i didn't know how to explain)
this is what i have for now
this is my code :
Widget _buildListItem(BuildContext context, DocumentSnapshot document) {
return ListTile(
title: Container(
margin: EdgeInsets.all(8.0),
padding: EdgeInsets.fromLTRB(210, 0.0, 0.0, 0.0),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(
color: Colors.pink[800], // set border color
width: 3.0), // set border width
borderRadius: BorderRadius.all(
Radius.circular(10.0)), // set rounded corner radius
boxShadow: [
BoxShadow(
blurRadius: 5,
color: Colors.black,
offset: Offset(0.5, 1))
] // make rounded corner of border
),
child: Row(
children: <Widget>[
Container(
child: Text(
document['rep'],
style: TextStyle(
fontSize: 50.0,
color: Colors.black,
),
),
)
]
),
),
onTap: () {
Firestore.instance.runTransaction(
(transaction) async {
DocumentSnapshot freshSnap =
await transaction.get(document.reference);
await transaction.update(freshSnap.reference, {
'votes': freshSnap['votes'] + 1,
});
});
},
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: StreamBuilder(
stream: Firestore.instance.collection('questions').snapshots(),
builder: (context, snapshot) {
if (!snapshot.hasData) return const Text('Loading ...');
return ListView.builder(
padding: EdgeInsets.fromLTRB(50.0, 300.0, 50.0, 0.0),
itemExtent: 100.0,
itemCount: snapshot.data.documents.length,
itemBuilder: (context, index) =>
_buildListItem(context, snapshot.data.documents[index]),
);
}),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(
context, MaterialPageRoute(builder: (context) => new Home()));
},
child: Text("Home"),
),
);
}
thank you so much !
Wrap list tile with colored container :
itemBuilder: (context, index){
return Container(
color: isSelected[index] ? Colors.blue : null,
child: ListTile(title:'test'),
);
}
Change selection status when item is taped.
ListTile(
title: Text('test'),
selected: isSelected[index],
onTap: () {
setState(() {
isSelected[index] = !isSelected[index];
});
},
),
final List<bool> isSelected;
Try it on DartPad