Every checkboxes are being checked when you select only one of them - flutter

I've created a button that allows the user to add a credit card, the cards are being added to a Listview.builder.
The problem is that when I have multiple cards and I select one, it selects all of them, it's probably a state problems but I didn't find (yet) how to fix it, here is the dartpad : [dartpad][1] of my code if you can check it and maybe show me what I'm doing wrong, it's probably failing inside the buildBody but I'm not really sure and I have not successfully found a solution yet.
You simply have to tap two times on 'Add a card' and you will see when checking one of them, both will get selected.
For some reason the link isnt working through the shortcut so here it is https://dartpad.dev/b0aaaa2901aa3ac67426d9bdd885abb1:

I modified your dartpad code to get the behaviour you are trying to achive:
The code is provided below:
The issue was that you are using the same bool value _isSelected for the two Checkboxes.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
body: Center(
child: InformationsBancairesPage(),
),
),
);
}
}
class InformationsBancairesPage extends StatefulWidget {
#override
_InformationsBancairesPageState createState() =>
_InformationsBancairesPageState();
}
class _InformationsBancairesPageState extends State<InformationsBancairesPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(
title: Text(
'Payer ou recevoir un paiement'.toUpperCase(),
style: TextStyle(fontSize: 19, color: Colors.black),
),
centerTitle: true,
backgroundColor: Colors.white,
iconTheme: IconThemeData(color: Colors.black),
),
body: Padding(
padding: const EdgeInsets.all(15.0),
child: ListView(
children: <Widget>[
InputAddCarte(),
],
),
),
);
}
}
class InputAddCarte extends StatefulWidget {
#override
_InputAddCarteState createState() => _InputAddCarteState();
}
class _InputAddCarteState extends State<InputAddCarte> {
// create a list of bool values for your checkboxes
List<bool> _selectedList = [false, false];
int value = 0;
void initState() {
super.initState();
}
_addCard() {
setState(() {
value = value + 1;
print(value);
});
}
Widget buildBody(BuildContext context, int indexClicked) {
return LabeledCheckbox(
label: 'Card credit',
padding: const EdgeInsets.symmetric(horizontal: 20.0),
// pass the value of the checkbox at the selected index
value: _selectedList[indexClicked],
onChanged: (bool newValue) {
setState(() {
// pass the value of the checkbox at the selected index
_selectedList[indexClicked] = newValue;
});
},
);
}
#override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
ButtonTheme(
minWidth: 250,
child: RaisedButton(
color: Color(0xff00cc99),
child: Text(
'ADD A CARD'.toUpperCase(),
style: TextStyle(color: Colors.white, fontSize: 18),
),
onPressed: _addCard,
),
),
// Show the cards when you press 'Ajouter une carte'
ListView.builder(
shrinkWrap: true,
itemCount: this.value,
itemBuilder: (BuildContext context, int value) {
// display two cards maximum
if (value < 2) {
// pass the index of the selected checkbox
return buildBody(context, value);
}
return Container();
},
),
ButtonTheme(
minWidth: 250,
child: RaisedButton(
color: Colors.orange,
child: Text(
'Delete a card'.toUpperCase(),
style: TextStyle(color: Colors.white, fontSize: 18),
),
onPressed: () {},
),
)
],
);
}
}
// Create custom checkbox for the list of cards
class LabeledCheckbox extends StatelessWidget {
const LabeledCheckbox({
this.label,
this.padding,
this.value,
this.onChanged,
});
final String label;
final EdgeInsets padding;
final bool value;
final Function onChanged;
#override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
onChanged(!value);
},
child: Padding(
padding: padding,
child: Row(
children: <Widget>[
Expanded(child: Text(label)),
Checkbox(
value: value,
onChanged: (bool newValue) {
onChanged(newValue);
},
),
],
),
),
);
}
}

Related

widget into List<Widget> does not update into build method even if i call setState

i have the following simple full code
import 'dart:developer';
import 'package:flutter/material.dart';
class Test extends StatefulWidget {
const Test({Key? key}) : super(key: key);
#override
State<Test> createState() => _TestState();
}
class _TestState extends State<Test> {
List myListWidget = [];
late bool isColorWhie = false;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: (){
setState(() {
myListWidget.add(
Container(
width: 50,
height: 50,
color: isColorWhie?Colors.white:Colors.red,
)
);
});
},
child: Scaffold(
backgroundColor: Colors.green,
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
...myListWidget,
TextButton(
onPressed: (){
setState(() {
isColorWhie = !isColorWhie; // here never update
log('done');
});
},
child: const Text('tab to Change color',style: TextStyle(color: Colors.white),)
)
],
),
),
),
);
}
}
i tap on any point on screen to add Container into myListWidget thn call setState(() {}); to update ui.
everything fine now but when i change the isColorWhie to true it should change the color to white but it never update !
i am totally confused why it does not update ? And how could i handle with this ?
For base color change, I am using a separate button, also switching the list value.
One thing variable does update the UI, you need to handle state inside the item(state-management property) or reinitialize the variable to get update state.
class Test extends StatefulWidget {
const Test({Key? key}) : super(key: key);
#override
State<Test> createState() => _TestState();
}
class _TestState extends State<Test> {
List<bool> myListWidgetState = [];
bool isColorWhie = false;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(
() {
myListWidgetState.add(isColorWhie);
},
);
},
child: Scaffold(
backgroundColor: Colors.green,
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
...myListWidgetState.map(
(e) {
return Container(
width: 50,
height: 50,
color: e ? Colors.white : Colors.red,
);
},
),
TextButton(
onPressed: () {
myListWidgetState = myListWidgetState.map((e) => !e).toList();
setState(() {});
print(isColorWhie);
},
child: const Text(
'tab to Change color',
style: TextStyle(color: Colors.white),
),
),
TextButton(
onPressed: () {
setState(() {
isColorWhie = !isColorWhie;
});
print(isColorWhie);
},
child: const Text(
'tab to Change base color',
style: TextStyle(color: Colors.white),
),
),
],
),
),
),
);
}
}
Since you create a container as an object in GestureDetector and save it to your list, it will not change. It is now permanently saved (of course as long as you do not delete the element) as an entry in your list.
Your logic works exactly as you programmed it. For example, if you were to recompile the app and press the TextButton and then anywhere on your screen, a white container would also appear.
If you want to dynamically change the color of all containers at once, then you can do the following:
class _TestState extends State<Test> {
int containerCounter = 0;
late bool isColorWhie = false;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() {
containerCounter++;
});
},
child: Scaffold(
backgroundColor: Colors.green,
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
width: 50,
child: ListView.builder(
shrinkWrap: true,
itemCount: containerCounter,
itemBuilder: ((context, index) {
return Container(
height: 50,
color: isColorWhie ? Colors.white : Colors.red,
);
}),
),
),
TextButton(
onPressed: () {
setState(() {
isColorWhie = !isColorWhie; // here never update
});
},
child: const Text(
'tab to Change color',
style: TextStyle(color: Colors.white),
))
],
),
),
),
);
}
}

OnTap Function in the DropDownMenu Button in Flutter

I've tried to populate the dropdown menu button with the data from the SQLite database.
Then on the onTap Function I wanted to navigate to the selected category.
When I tap on the category it does not navigate.
I have saved each category with an id in the database which is used the identify the selected item.
Here is the code:
'''
class _HomeState extends State<Home> {
TodoService _todoService;
var _selectedValue;
var _categories = List<DropdownMenuItem>();
List<Todo>_todoList=List<Todo>();
#override
initState(){
super.initState();
_loadCategories();
}
_loadCategories() async {
var _categoryService = CategoryService();
var categories = await _categoryService.readCategory();
categories.forEach((category) {
setState(() {
_categories.add(DropdownMenuItem(
child: Text(category['name']),
value: category['name'],
onTap: ()=>Navigator.of(context).push(MaterialPageRoute(builder:(context)=>TodosByCategory(category: category['name'],))),
));
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _globalKey,
appBar: AppBar(
actions: <Widget>[
DropdownButtonHideUnderline(
child: DropdownButton(
value: _selectedValue,
items: _categories,
dropdownColor: Colors.blue,
style: TextStyle(color: Colors.white,fontSize: 16.0),
iconDisabledColor: Colors.white,
iconEnabledColor: Colors.white,
onChanged: (value) {
setState(() {
_selectedValue = value;
});
},
),
),
'''
Here is the todosByCategory():
'''
class _TodosByCategoryState extends State<TodosByCategory> {
List<Todo>_todoList=List<Todo>();
TodoService _todoService=TodoService();
#override
initState(){
super.initState();
getTodosByCategories();
}
getTodosByCategories()async{
var todos=await _todoService.readTodoByCategory(this.widget.category);
todos.forEach((todo){
setState(() {
var model= Todo();
model.title=todo['title'];
model.dueDate=todo['dueDate'];
_todoList.add(model);
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Todos By Category'),
),
body: Column(
children: <Widget>[
Expanded(
child: ListView.builder(
itemCount: _todoList.length,
itemBuilder: (context, index){
return Padding(
padding: EdgeInsets.only(top:8.0, left: 8.0, right: 8.0),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(0),
),
elevation: 8.0,
child: ListTile(
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text(_todoList[index].title)
],
),
subtitle: Text(_todoList[index].dueDate),
// trailing: Text(_todoList[index].dueDate),
),
),
);
},),
)
],
),
);
}
}
'''
Please help me out.
Instead of writing the navigation code inside onTap of DropdownMenuItem, you can write it inside onChanged of DropdownButton where you are also getting the category name string as the value. It should work then.

how to change layout in Flutter

I've been trying to design the layout of my ExpansionTile just like the design below but I couldn't figure out how to change the layout. any suggestion on how to change the border radius, change the background color and also make a gap between each other?.
I tried adding boxDecoration in each container but the style only apply to outside but not on each expansionTile.
import 'package:flutter/material.dart';
class MyReoderWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ReorderItems(topTen: ['j']);
}
}
class DataHolder {
List<String> parentKeys;
Map<String, List<String>> childMap;
DataHolder._privateConstructor();
static final DataHolder _dataHolder = DataHolder._privateConstructor();
static DataHolder get instance => _dataHolder;
factory DataHolder.initialize({#required parentKeys}) {
_dataHolder.parentKeys = parentKeys;
_dataHolder.childMap = {};
for (String key in parentKeys) {
_dataHolder.childMap.putIfAbsent(
}
return _dataHolder;
}
}
class ReorderItems extends StatefulWidget {
final List<String> topTen;
ReorderItems({this.topTen});
#override
_ReorderItemsState createState() => _ReorderItemsState();
}
class _ReorderItemsState extends State<ReorderItems> {
#override
void initState() {
super.initState();
// initialize the children for the Expansion tile
// This initialization can be replaced with any logic like network fetch or something else.
DataHolder.initialize(parentKeys: widget.topTen);
}
#override
Widget build(BuildContext context) {
return PrimaryScrollController(
key: ValueKey(widget.topTen.toString()),
controller: ScrollController(),
child: Container(
decoration: BoxDecoration(),
child: ReorderableListView(
onReorder: onReorder,
children: getListItem(),
),
),
);
}
List<ExpansionTile> getListItem() => DataHolder.instance.parentKeys
.asMap()
.map((index, item) => MapEntry(index, buildTenableListTile(item, index)))
.values
.toList();
ExpansionTile buildTenableListTile(String mapKey, int index) => ExpansionTile(
key: ValueKey(mapKey),
title: Text(mapKey),
leading: Icon(Icons.list),
children: [
Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(20))
),
key: ValueKey('$mapKey$index'),
height: 200,
child: Container(
padding: EdgeInsets.only(left: 30.0),
child: ReorderList(
parentMapKey: mapKey,
),
),
),
],
);
void onReorder(int oldIndex, int newIndex) {
if (newIndex > oldIndex) {
newIndex -= 1;
}
setState(() {
String game = widget.topTen[oldIndex];
DataHolder.instance.parentKeys.removeAt(oldIndex);
DataHolder.instance.parentKeys.insert(newIndex, game);
});
}
}
class ReorderList extends StatefulWidget {
final String parentMapKey;
ReorderList({this.parentMapKey});
#override
_ReorderListState createState() => _ReorderListState();
}
class _ReorderListState extends State<ReorderList> {
#override
Widget build(BuildContext context) {
return PrimaryScrollController(
controller: ScrollController(),
child: ReorderableListView(
// scrollController: ScrollController(),
onReorder: onReorder,
children: DataHolder.instance.childMap[widget.parentMapKey]
.map(
(String child) => Container(
child: ListTile(
key: ValueKey(child),
leading: Icon(Icons.list),
title: Text(child),
),
),
)
.toList(),
),
);
}
void onReorder(int oldIndex, int newIndex) {
if (newIndex > oldIndex) {
newIndex -= 1;
}
List<String> children = DataHolder.instance.childMap[widget.parentMapKey];
String game = children[oldIndex];
children.removeAt(oldIndex);
children.insert(newIndex, game);
DataHolder.instance.childMap[widget.parentMapKey] = children;
// Need to set state to rebuild the children.
setState(() {});
}
}
You can do it using custom expandable container.
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Calendar',
theme: ThemeData(
primarySwatch: Colors.grey,
),
debugShowCheckedModeBanner: false,
home: Material(
child: MyReoderWidget(),
),
);
}
}
class CustomModel {
String title;
bool isExpanded;
List<String> subItems;
CustomModel({this.title, this.subItems, this.isExpanded = false});
}
class MyReoderWidget extends StatefulWidget {
#override
_MyReoderWidgetState createState() => _MyReoderWidgetState();
}
class _MyReoderWidgetState extends State<MyReoderWidget> {
List<CustomModel> listItems;
#override
void initState() {
super.initState();
listItems = List<CustomModel>();
listItems.add(CustomModel(
title: "App Name 1", subItems: ["Card Name 1", "Card Name 2"]));
listItems.add(CustomModel(
title: "App Name 2", subItems: ["Card Name 3", "Card Name 4"]));
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: ListView(
children: listItems
.map((model) => new Padding(
padding: EdgeInsets.only(
bottom: 10,
),
child: ExpandableCardContainer(
isExpanded: model.isExpanded,
collapsedChild: createHeaderCard(model),
expandedChild: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(
bottom: 10,
),
child: createHeaderCard(model),
)
]..addAll(model.subItems
.map((e) => createChildCard(e))
.toList()),
),
),
))
.toList()),
);
}
Widget createHeaderCard(CustomModel model) {
return Container(
child: Row(
children: <Widget>[
Icon(
Icons.more_vert,
color: Colors.white,
),
Expanded(
child: Text(
model.title,
style: TextStyle(color: Colors.white),
),
),
GestureDetector(
onTap: () {
setState(() {
model.isExpanded = !model.isExpanded;
});
},
child: Icon(
model.isExpanded
? Icons.keyboard_arrow_up
: Icons.keyboard_arrow_down,
color: Colors.white,
),
)
],
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Color(0xFF132435),
),
height: 50,
);
}
Widget createChildCard(String subItems) {
return Container(
margin: EdgeInsets.only(left: 30, bottom: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
Icons.more_vert,
color: Colors.white,
),
Expanded(
child: Text(
subItems,
style: TextStyle(color: Colors.white),
),
),
],
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
color: Color(0xFF132435),
),
height: 50,
);
}
}
class ExpandableCardContainer extends StatefulWidget {
final bool isExpanded;
final Widget collapsedChild;
final Widget expandedChild;
const ExpandableCardContainer(
{Key key, this.isExpanded, this.collapsedChild, this.expandedChild})
: super(key: key);
#override
_ExpandableCardContainerState createState() =>
_ExpandableCardContainerState();
}
class _ExpandableCardContainerState extends State<ExpandableCardContainer> {
#override
Widget build(BuildContext context) {
return new AnimatedContainer(
duration: new Duration(milliseconds: 200),
curve: Curves.easeInOut,
child: widget.isExpanded ? widget.expandedChild : widget.collapsedChild,
);
}
}

Flutter :- How to display dynamic widgets on screen?

I want to show entered text in scrambled form. ie, each letter of the word need to display in individual Container in a row. For this, I am taking text input, storing it in List<String> and then scrambling it using shuffle() and then using List.generate to return Container with Text, as below:
List<Widget> _generateJumble(String input) {
inputList = input.split('');
var shuffleList = inputList.toList()..shuffle();
print(shuffleList);
return List<Widget>.generate(shuffleList.length, (int index) {
return Container(
width: 50,
color: Colors.blue,
child: Text(shuffleList[index].toString(),
style: TextStyle(color: Colors.white),
)
);
});
}
I am calling above method onTap of a button upon which the scrambled form of the input should be displayed. But I am not sure how to display the result of above method in UI. How should I use this method so that the returning Container based on shuffleList.length will be displayed in UI as below ?
RaisedButton(
onPressed: () {},
child: Text('Clear'),
)
],
),
),
Row(
children: <Widget>[
// ? _displayJumble()
]
)
This is my solution:
1) Press a button, scrable the string and set it to the a list
2) setState and show the list to the user
This is the widget code:
class _MyHomePageState extends State<MyHomePage> {
List<String> inputList = [];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Wrap(
children: inputList.map((s) {
return Container(
width: 50,
color: Colors.blue,
child: Text(
s,
style: TextStyle(color: Colors.white),
),
);
}).toList(),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
_generateJumble('Random string');
});
},
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
List<Widget> _generateJumble(String input) {
inputList = input.split('');
inputList = inputList.toList()..shuffle();
print(inputList);
}
}
I used the widget Wrap because automatically wrap the widget when there is no space available for it. You can use whatever you like to use.
This is the screen result:
Before press the button:
After press the button:
Please check the below solution of it, I have used the Wrap widget for it
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutterlearningapp/colors.dart';
class HomeScreen extends StatefulWidget {
var inputVales;
#override
State<StatefulWidget> createState() {
// TODO: implement createState
return _HomeScreen();
}
}
class _HomeScreen extends State<HomeScreen> {
List<String> charcaterArray = new List<String>();
#override
Widget build(BuildContext context) {
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text("Home"),
),
body: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.all(10.0),
child: TextField(
decoration: InputDecoration(labelText: 'Enter Words'),
onChanged: (text) {
setState(() {
widget.inputVales = text;
charcaterArray.clear();
for (var i = 0; i < widget.inputVales.length; i++) {
var character = widget.inputVales[i];
if (character != " ") {
charcaterArray.add(character);
}
}
});
},
),
),
Wrap(
spacing: 6.0,
runSpacing: 6.0,
children:
List<Widget>.generate(charcaterArray.length, (int index) {
return Container(
height: MediaQuery.of(context).size.height * 0.1,
width: MediaQuery.of(context).size.width * 0.1,
decoration: BoxDecoration(
color: Colors.lightGreen,
borderRadius: BorderRadius.all(Radius.elliptical(4.0, 4.0)),
),
child: Center(
child: Text(
charcaterArray[index],
style:
TextStyle(color: Colors.deepOrange, fontSize: 20.0),
),
),
);
/*Chip(
label: Text(charcaterArray[index]),
onDeleted: () {
setState(() {
charcaterArray.removeAt(index);
});
},
);*/
}),
)
],
));
}
}
And here is the output of it

How to create a Checkbox and access global variable from class?

I am trying to create a checkbox inside my view. I declared bool variable isChecked= false in my state class, and while writing constructor for checkbox getting the error on my isChecked variable as 'Only static members can be accessed in intializers'. I made the variable as static, which removed the error on bool variable, but giving the same error on setState(). How do i resolve this ?
import 'package:flutter/material.dart';
class CardScreen extends StatelessWidget{
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Card Screen',
home: new myPetScreen()
);
}
}
class myPetScreen extends StatefulWidget{
myPetScreen({Key key, this.title}) : super(key: key);
final String title;
#override
_myPetScreenState createState() => new _myPetScreenState();
}
class _myPetScreenState extends State<myPetScreen>{
static bool isChecked = false;
final view = new Column(
children: <Widget>[
//did other UI Implementation here
Container(
child: Flexible(
child: ListView.builder(itemBuilder: (context, position){
return Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: <Widget>[
Text(position.toString(), style: TextStyle(fontSize: 14.0, color: Colors.black),),
Spacer(),
Checkbox(
value: isChecked,
onChanged: (value) {
setState(() {
isChecked = value;
});
},
),
],
),
)
);
}
),
),
) ,
],
);
#override Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Card Screen')),
body: view,
);
}
}
make some change take your column code into one method then that method called into widget..
like this way..
Column getView(){
var view = new Column(
children: <Widget>[
//did other UI Implementation here
Container(
child: Flexible(
child: ListView.builder(itemBuilder: (context, position) {
return Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
children: <Widget>[
Text(
position.toString(),
style: TextStyle(fontSize: 14.0, color: Colors.black),
),
Spacer(),
Checkbox(
value: isChecked,
onChanged: (value) {
changeState(value);
},
),
],
),
));
}),
),
),
],
);
return view;
}
after that called this way..
body: getView()
You are declaring view as a final variable, so it is immutable. change it to a function like so:
Widget get view => Container(
//...
)
Also, don't forget to remove static from the state declaration (Never do that in a stateful wiget).