Create a new Card using onPressed() - flutter

When the user clicks the FAB, i want it to create a new Card widget wrapped in a GestureDetector. I have created a list of type widget and also created a function with a setState to add to the list and display it in a SliverGrid. but when i click the FAB, it doesnt seem to be adding.
Could i get a small guide on how to add a Card using an FAB. (or adding any type of widget in a SliverGrid).
the list : List<Widget> cardList = <Widget>[];
function for adding items to the list :
void addItems() async{
setState(() {
cardList.insert(0, GestureDetector(
onTap: () async {
await Navigator.push( context, MaterialPageRoute(
builder: (context) => TodoList(), // this just navigates to another screen ; not important in this question
)
);
},
child: Card(
child:Center(child: whitefontstylemont(text: "project 1", size:20,)) //this is just a custom TextStyle
),
));
});
}
the floating action button which adds a new Card to the list :
floatingActionButton: FloatingActionButton( // this is inside a Scaffold
onPressed: ()async {
setState(() {
addItems();
});
},
heroTag: "btn2",
child: Icon(Icons.add, color: Color(whitecolor),), backgroundColor: Color(redcolor),),
the SliverGrid where i want a new card to be displayed :
SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2
),
delegate: new SliverChildBuilderDelegate((context, index) {
return cardList[index];
},
childCount: cardList.length // this is where i want a new Card to be displayed
)
),

Related

Flutter Slidable - How to remove the slidable item from the list when i hit the delete button?

I have a simple list of ListTile s that I nested in Slidable widget using the flutter_slidable package. However there is one issue that when I use the delete button, the item stays on the screen, even though it is successfully removed from the list (If i make a hot reload, it will actually get removed from screen). I tried to add a setState method inside the onPressed function but I cannot add it because the SlidableAction widget is a stateless widget. How can I make the item disappear when I tap on this button?
Here is a small video demonstration. I delete two lists with the delete button. They stay on the screen. I go home screen and come back to see they got deleted.
https://streamable.com/td7blf
Here is my code:
Expanded(
child: ListView.builder(
itemCount: likedNames.length,
itemBuilder: (context, index) {
return Slidable(
key: const ValueKey(0),
endActionPane: ActionPane(
motion: ScrollMotion(),
dismissible: DismissiblePane(onDismissed: () {
likedNames.remove(likedNames[index]);
}),
children: [
SlidableAction(
onPressed: (context) {
likedNames.remove(likedNames[index]); // <- this is the part where I want to do the removing of the item
},
label: 'Delete',
backgroundColor: AppColors.error,
),
],
),
child: ListTile(
onTap: () {},
title: Text(likedNames[index].name),
trailing: Icon(Icons.chevron_right),
),
);
}),
),
onPressed: (context) {
setState() => likedNames.remove(likedNames[index])
},
I've used this solution:
onPressed: (BuildContext context) async {
await Provider.of<MyList>(context, listen: false)
.remove(MyList[index]);
}
MyList is a separate class:
class MyList extends ChangeNotifier
Whit this methods:
final List<String> _myList = [];
List<String> get items => _myList;
.
.
.
Future<bool> remove(String item) async {
_myList.remove(item);
notifyListeners();
return true;
}

How to add a card widget dynamically whenever floating action button is clicked in flutter?

I am very new to flutter and was just curious to know how can we create a new card widget everytime a button (lets say FAB) is clicked.
Suppose this is the card widget :
return Card(
child: Column(
children: [
Text('name'),
Text('standard'),
Text('Roll No'),
],
),
);
I want the cards to build with the same content everytime the FAB is clicked. Can someone help me with this ?
First declare a List of widget type
List<Widget> _cardList = [];
Then create your widget which you want to add on button click, e.g.
Widget _card() {
return Card(
child: Column(
children: [
Text('name'),
Text('standard'),
Text('Roll No'),
],
),
);
}
add your widget in List on button click
FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
setState(() {
_cardList.add(_card());
});
},
),
Now use a ListView.builder for create a list of widget
ListView.builder(
shrinkWrap: true,
itemCount: _cardList.length,
itemBuilder: (context, index) {
return _cardList[index];
},
)

Flutter Disable Button on ListView Builder

Hi I am trying to i have a listview.builder which renders custom card design that i create the problem is that i want to disable button on the card on which user tap but it end up disabling all the cards button
here is the code
Expanded(
child: ListView.builder(
itemCount: list.length,
itemBuilder: (context, i) {
return CardDesign(
index: i,
infolist: list,
buttonOnTap: () async {
await updateJoin(list[i].joined += 1, list[i].id);
setState(() {});
},
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => DetailsScreen(
tournamentinfo: list[i],
),
),
);
},
);
}),
the buttonOnTap Method is the one that i want to disable but only for that Specific button in the list and only for that user

Call SnackBar from within an AlertDialog

When a user clicks on delete for an employee, an AlertDialog shall pop up to warn the user.
If the user confirms the deletion, then the AlertDialog disappears and at the bottom of the Scaffold a SnackBar should appear with an Undo function.
Problem:
When I implement the SnackBar method showSnackBar(context, index, employee) within the AlertDialog class I get the following error:
he following assertion was thrown while handling a gesture:
Scaffold.of() called with a context that does not contain a Scaffold.
showDeleteDialog(BuildContext context, Employee employee, int index) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title:
Text('Are you sure you want to delete: ${employee.name} ?'),
actions: <Widget>[
Row(
children: <Widget>[
FlatButton(
child: Text('Yes'),
onPressed: () {
DatabaseProvider.db.deleteEmployee(employee.id).then(
(_) => BlocProvider.of<EmployeeBloc>(context)
.add(DeleteEmployee(index)));
Navigator.pop(context,employee);
showSnackBar(context, index, employee);
}),
FlatButton(
child: Text('No!'),
onPressed: () => Navigator.pop(context)),
],
)
],
));
}
Instead, I thought I could return an employee from the showDeleteDialog when I confirm the deletion. When the result is not null, then I should show the SnackBar. I tried to implement this with Future/Async but with no success.
onPressed: () async {
Employee deletedEmployee = await showDeleteDialog(context, employee, index);
await showSnackBar(context, index, deletedEmployee);
},
Edit: I would like to avoid using GlobalKey if possible, since I read it is not good for the App's performance.
As the error says Scaffold.of() called with a context that does not contain a Scaffold., that means the current context that you are passing to showSnackBar() method doesn't contain a Scaffold in the immediate parent.
We can fix this by using GlobalKey and assign it to the Scaffold. Declare a global key in your stateful widget and pass this as a key in your Scaffold, as below:
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
....
return Scaffold(
key: _scaffoldKey,
appBar: AppBar(
title: Text(widget.title),
),
I call a method _showSnackBar() after navigator.pop() on OK button click inside the alertDialog, as below:
return AlertDialog(
title: Text('Not in stock'),
content: const Text('This item is no longer available'),
actions: <Widget>[
FlatButton(
child: Text('Ok'),
onPressed: () {
Navigator.of(context).pop();
_showSnackBar();
},
),
],
);
Then in the _showSnackBar() method, use the key to show the snackbar, as below:
void _showSnackBar() {
_scaffoldKey.currentState.showSnackBar(
SnackBar(
content: Text('Snackbar is displayed'),
));
}
With this approach, once you tap on OK button on alertDialog, the dialog will close and you'll see the snackbar. You may need to customize this per your code as you shared above.
Hope this answers your question and resolves your issue.
Found the solution and it is super easy...
I only had to re-name one of the context to a dialogContext
showDeleteDialog(BuildContext context, Employee employee, int index) {
showDialog(
context: context,
builder: (dialogContext) => AlertDialog(
title:
Text('Are you sure you want to delete: ${employee.name} ?'),
actions: <Widget>[
Row(
children: <Widget>[
FlatButton(
child: Text('Yes'),
onPressed: () {
DatabaseProvider.db.deleteEmployee(employee.id).then(
(_) => BlocProvider.of<EmployeeBloc>(dialogContext)
.add(DeleteEmployee(index)));
Navigator.pop(dialogContext);
showSnackBar(context, index, employee);
}),
FlatButton(
child: Text('No!'),
onPressed: () => Navigator.pop(context)),
],
)
],
));
}

Can a Card widget display a ListTile?

In this app, when the user clicks the FAB, it returns a Card wrapped in a GestureDetector. when the user clicks on a displayed card, the GestureDetector will navigate them to another page. I want to implement a delete function so that i can dismiss a Card.
So i defined the child: of the Card as a ListTile with a trailing Icon which is supposed to delete that particular Card. But when i add a Card, it only displays the title: and does not display the trailing Icon.
The Cards are displayed in a SliverGrid with a crossAxisCount = 2.
question: do Card widgets support displaying a ListTile with a trailing widget or is my implementation wrong?
P.S. i have tried setting crossAxisCount = 1 but it still does not show the trailing Icon.
card generating function:
void addItems() async {
setState(() {
cardList.insert(0, new GestureDetector(
onTap: () async {
await Navigator.push(context, MaterialPageRoute(
builder: (context) =>
TodoList(), // this just navigates to another screen ; not important in this question
)
);
},
child: Card(
child: ListTile(
title: Text("project 1"),
trailing: new Icon(Icons.remove_circle,
color: Colors.redAccent,),
// subtitle: whitefontstylemont(text: "project 1", size: 20,)) //this is just a custom TextStyle
),
)
));
});
}
card deleting function:
_deleteNoDo(int index) async {
debugPrint("Deleted Item!");
setState(() {
cardList.removeAt(index);
});
}
complete example (excluding above mentioned functions):
class _Starting_screenState extends State<Starting_screen> {
int _count = 0;
#override
Widget build(BuildContext context) {
List<Widget> cardList = new List.generate(
_count, (int i) => new createCard());
SystemChrome.setEnabledSystemUIOverlays([]);
// _deleteNoDo(int index) async {
// debugPrint("Deleted Item!");
// setState(() {
// cardList.removeAt(index);
// });
// }
//
// void addItems() async {
// setState(() {
// cardList.insert(0, new GestureDetector(
// onTap: () async {
// await Navigator.push(context, MaterialPageRoute(
// builder: (context) =>
// TodoList(), // this just navigates to another screen ; not important in this question
// )
// );
// },
// child: Card(
// child: ListTile(
// title: Text("project 1"),
// trailing: new Icon(Icons.remove_circle,
// color: Colors.redAccent,),
//// subtitle: whitefontstylemont(text: "project 1", size: 20,)) //this is just a custom TextStyle
// ),
// )
// ));
// });
// }
return Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () async {
setState(() {
_count += 1;
});
},
heroTag: "btn2",
child: Icon(Icons.add, color: Color(whitecolor),), // this is just a custom color
backgroundColor: Color(redcolor),), // this is just a custom color
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
pinned: true,
flexibleSpace: FlexibleSpaceBar(
),
actions: <Widget>[
Expanded(
child: Padding(
padding: const EdgeInsets.only(top: 20, right: 10),
child: whitefontstyle(text: "Remaining tasks for today - ${cardList.length}", size: 20,), // this is just a custom textstyle
),
),
],
),
SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2
),
delegate: new SliverChildBuilderDelegate((context,
index) {
return cardList[index]; // this is where the cards are displayed in a list
},
childCount: cardList.length
)
),
]
)
);
}
}
actual result:
expected result (assume only displaying title and trailing icon as shown below):
Are you sure that you are calling the right methods. Cause there are few things which are not in place or you haven't shared the right code. I will address them below.
First of all the alignment of child text in card. It is in center of the card but there is no center property used in your code. Card widget does not auto align the text.
Second adding the items. You post the code of addItems function but also added another function in build with name createCard. So we don't know if that createCard have the same widget tree as the addItems function or not.
Its not working not so you are not seeing it but even if you are able to see the Icon widget you still won't be able to delete the item. The reason being is its a non-clickable widget. You should be using the IconButton widget if you want to add the click functionality on it.
These are my finding in your code. If you can review them or either share the correct code, may be I am able to help more.