Icon does not changed on tapping in flutter custom widget - flutter

I have created a custom widget for list tile where I need to change icon of fav_outline to fav or google but it does not change, although items are adding and removing working properly but only icon does not change..it was working well before I created a custom widget for it
I have BottomNavigation for two screens alimonies and fav movies like that...
when I click on fav icon of all movie screen...it adds to fav movie ,,that's working fine, but only icon does not change
here is my coding of custom widget and my all movie screen..both are stateful
class MyCard extends StatefulWidget {
final Movie e;
final VoidCallback onfavtab;
MyCard({required this.e,required this.onfavtab});
#override
State<MyCard> createState() => _MyCardState();
}
class _MyCardState extends State<MyCard> {
#override
Widget build(BuildContext context) {
return Card(
child: ListTile(
title: Text(widget.e.name.toString()),
subtitle: Text(widget.e.language),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: userlist[0].favmovies.contains(e)==true?Icon(Icons.favorite): Icon(Icons.favorite_outline),onPressed: widget.onfavtab),
IconButton(onPressed: (){}, icon: Icon(Icons.delete)),
],
),
leading: CircleAvatar(
backgroundImage: NetworkImage(widget.e.imageurl),
),
),
);
}
}
and here is my allmovie screen coding where I call custom widget
lass _AllMoviesState extends State<AllMovies> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView(children: movielist.map((e) => MyCard(e: e, onfavtab: (){
if(userlist[0].favmovies.contains(e)==true)
userlist[0].favmovies.remove(e);
else
userlist[0].favmovies.add(e);
//looks like this is not working
setState(() {
print(userlist[0].favmovies);
});
},
)).toList(),),
);
}
}

put the icon which you need to edit it in provider class
and whene you click it just change the icon and notify it.

Related

How do I change bookmark_outline to bookmark onPressed?

Here's what I have...
IconButton(icon: Icon (Icons.bookmark_outline, color: Color(0xFF192A4F),),
onPressed: () => Icons.bookmark, color: Color(0xFF192A4F),),
I don't know what I'm doing. All I've been able to find is this
how to fill color of IconButton in Flutter
but I couldn't get that to work.
I just want the icon to change when tapped... I'm new.
What worked:
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
bool outline = false;
#override
Widget build(BuildContext context) {
return DefaultTabController(
Row(
children: <Widget>[
IconButton(icon: Icon(outline ? Icons.bookmark_outline : Icons.bookmark),
onPressed:(){
setState((){
outline = !outline;
});
}
),
SizedBox(width: 8.0),
Text('Bookmark', style: TextStyle(color: Color(0xFF192A4F)),),
],
),
you need do like this,
create a boolean variable,
bool outline = false;
now in the on press function,
onPressed:(){
setState(){
outline = !outline;
}
}
now for the your Icon do something like this,
icon: Icon(outline ? Icons.bookmark_outline : Icons.bookmark):
Make sure your are using stateful widget

Flutter SetState from custom widget (or more down the line)

I have a simple flutter app. It has a stateful widget in the Home Page with a simple Scaffold which only has a Column. One of the children in the column is a custom widget called buildBodyLayout(). This widget has its own column with some Text widgets, and another custom widget called buildButton(). This new widget has a button which needs to setState of a variable in the Home view. I pass the value of the variable when calling the widget. But each widget is in its own dart file since I am re-using the same widget in other pages.
How do I setState the main stateful widget from inside custom widgets?
If I write everything inside the same page, it all works fine. How do I use a widget in a different dart file to set the sate of a parent widget?
Sample Code
Home Stateful Widget
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int changeValue;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Text("Welcome to my App"),
Text("The Change Value is: $changeValue"),
buildBodyLayout(changeValue),
],
),
);
}
}
buildBodyLayouot Widget
Widget buildBodyLayout(int value){
return Column(
children: [
Text("Press the + and - Buttons to change Value"),
buildButtons(value),
],
);
buildButtons Widget
Widget buildButtons(int value){
return Column(
children: [
RaisedButton(
child: Text("Increase Value"),
onPressed: (){
value = value + 1; //THIS SHOULD SET STATE
}) ,
RaisedButton(
child: Text("Decrease Value"),
onPressed: (){
value = value - 1; //THIS SHOULD SET STATE
})
],
);
}
}
Thank you for any help!
Widgets in flutter are classes that extend the widget(StatefulWidget, StatelessWidget) class.
In your code your using functions to build your widgets, which is not recommended.
You can see the difference between class widgets and function widgets here:
What is the difference between functions and classes to create reusable widgets?
Aside from that, using function or classes, to solve your problem you need to use a callback.
class Home extends StatefulWidget {
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
int changeValue = 0;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
Text("Welcome to my App"),
Text("The Change Value is: $changeValue"),
buildBodyLayout(changeValue,
addToValue: (int increment){
setState((){
changeValue += increment;
});
}
),
],
),
);
}
}
Widget buildBodyLayout(int value, Function(int newValue) addToValue){
return Column(
children: [
Text("Press the + and - Buttons to change Value"),
buildButtons(value, addToValue),
],
);
}
Widget buildButtons(int value, Function(int newValue) addToValue){
return Column(
children: [
RaisedButton(
child: Text("Increase Value"),
onPressed: (){
addToValue(1);
}),
RaisedButton(
child: Text("Decrease Value"),
onPressed: (){
addToValue(-1);
})
],
);
}
You also don't need to put your widgets in different files to reuse them, but it's recommended that you do that.

Flutter navigation drawer and "deletes" state of stateful widget

I have a small flutter application with several stateful and stateless widgets.
My drawer widget looks like follows:
class AppDrawer extends StatelessWidget{
#override
Widget build(BuildContext context) {
return Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
_createDrawerHeader(),
ListTile(
title: Text('Scenario'),
onTap: () {
Navigator.pop(context);
Navigator.pushReplacementNamed(context, Routes.scenario);
},
),
...
This works fine for switche between my widgets. I now have a simple counter widget that stores a counter variable in its state.
class Counter extends StatefulWidget {
static const String routeName = '/Counter';
int _counter = 0;
#override
_CounterState createState() => new _CounterState();
}
class _CounterState extends State<Counter> {
void _increment() {
setState(() {
widget._counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Row(
children: <Widget>[
new RaisedButton(
onPressed: _increment,
child: new Text('Increment'),
),
new Text('Count: ${widget._counter}'),
],
),
drawer: AppDrawer(),
);
}
}
If I switch between this and my other widgets with the drawer and go back to the counter widgets the counter is always 0. Looks like the state is initialized everytime.
I am a beginner using flutter and I thougt I can save a variable within this state. I think I am wrong. As my search didn't get my some usable results maybe you can give me an idea how to solve this or just provide some links with information.
Thanks for your help :)
I suggest learning some sort of State Management practice's. You will eventually need to learn this because this is an essential step.Try provider its easy and simple to use.

Flutter, How to update a text in an item in listview after updating the content from it's detail view?

I am following this link,
https://medium.com/…/developing-for-multiple-screen-sizes-a…
to create a master detail ipad application.
I have a scenario, there is a text field and button in detail page. When i change the text field value and press the button, the listview item (in left side) at that specific index also should be updated. can somebody suggest a work around?
You can return the edited object using Navigator.pop(context,object) to the Navigator.push() caller. I wrote an example app for you.
the data class:
class Item {
final String name;
Item(this.name);
}
the home page, where I display the item:
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
Item item = Item('ali2236');
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
child: Center(
child: Column(
children: <Widget>[
Text(item.name),
FlatButton(
child: Text('edit'),
onPressed: () {
Navigator.of(context)
.push(MaterialPageRoute(builder: (context) {
return ItemEditingPage(
item: item,
callbackFunction: (editedItem){
setState(() {
item = editedItem;
});
},
);
}));
},
),
],
),
),
),
);
}
}
and the editing page:
class ItemEditingPage extends StatefulWidget {
final Item item;
final void Function(Item item) callbackFunction;
const ItemEditingPage({Key key, this.item, this.callbackFunction}) : super(key: key);
#override
_ItemEditingPageState createState() => _ItemEditingPageState();
}
class _ItemEditingPageState extends State<ItemEditingPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
child: Center(
child: FlatButton(
child: Text('change name to aligator'),
onPressed: () {
///
/// if the name is [final], you create a new Item and pass it back
///
Item item = Item('aligator');
widget.callbackFunction(item);
///
/// if the name is not final you can just change it on the current object
///
//widget.item.name = 'aligator';
//widget.callbackFunction(widget.item);
},
),
),
),
);
}
}
edit: used a callback function instead of Navigator.pop() to notify the showcase page.

Fix last element of ListView to the bottom of screen

I am trying to implement a custom navigation drawer using Flutter. I would like to attach log out option to the bottom of the drawer. The problem is that number of elements above log out option is unknow (from 3 to 17).
So if these widgets take half of the space of a drawer, then log out option will be on the bottom, and if there is too much of them and you have to scroll to see them all, then the log out option will be simply the last.
I am also trying to give the first two options a green background color. Which widget tree would you recommend me? I had a thought about the ListView widget, it takes List of widgets as an argument in constructor.
Therefore I can solve the different background color for the first two items. But I still can't figure out how to attach the log out option to the bottom. In this case it's at the bottom of drawer, but it can happen, that other options will be bigger than screen size and in that case, it should be placed at the bottom of whole list.
EDIT: I've add a design to the question. The logout option is the one called Odhlášení. In this case it's at the bottom of drawer, but it can happen, that other options will be bigger than the screen size and in that case, it should be placed at the bottom of whole list.
Design:
You can simply use ListView to manage the "17" navigation options. Wrap this ListView inside an Column. The ListView will be the first child of the Column the second child, therefore placing at the bottom, will be your logout action.
If you are using transparent widgets (like ListTile) inside your ListView to display the navigation options, you can simply wrap it inside a Container. The Container, besides many other widgets, allows you to set a new background color with its color attribute.
Using this approach the widget tree would look like the following:
- Column // Column to place your LogutButton always below the ListView
- ListView // ListView to wrap all your navigation scrollable
- Container // Container for setting the color to green
- GreenNavigation
- Container
- GreenNavigation
- Navigation
- Navigation
- ...
- LogOutButton
Update 1 - Sticky LogOutButton :
To achieve the LogOutButton sticking to the end of the ListView you'll neeed to do two things:
Replace the Expanded with an Flexible
Set shrinkWrap: true inside the ListView
Update 2 - Spaced LogOutButton until large List:
Achieving the described behavior is a more difficult step. You'll have to check if the ListView exceeds the screen and is scrollable.
To do this I wrote this short snippet:
bool isListLarge() {
return controller.positions.isNotEmpty && physics.shouldAcceptUserOffset(controller.position);
}
It will return true if the ListView exceeds its limitations. Now we can refresh the state of the view, depending on the result of isListViewLarge. Below again a full code example.
Standalone code example (Update 2: Spaced LogOutButton until large List):
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(),
drawer: MyDrawer(),
),
);
}
}
class MyDrawer extends StatefulWidget {
#override
_MyDrawerState createState() => _MyDrawerState();
}
class _MyDrawerState extends State<MyDrawer> {
ScrollController controller = ScrollController();
ScrollPhysics physics = ScrollPhysics();
int entries = 4;
#override
Widget build(BuildContext context) {
Widget logout = IconButton(
icon: Icon(Icons.exit_to_app),
onPressed: () => {setState(() => entries += 4)});
List<Widget> navigationEntries = List<int>.generate(entries, (i) => i)
.map<Widget>((i) => ListTile(
title: Text(i.toString()),
))
.toList();
if (this.isListLarge()) { // if the List is large, add the logout to the scrollable list
navigationEntries.add(logout);
}
return Drawer(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween, // place the logout at the end of the drawer
children: <Widget>[
Flexible(
child: ListView(
controller: controller,
physics: physics,
shrinkWrap: true,
children: navigationEntries,
),
),
this.isListLarge() ? Container() : logout // if the List is small, add the logout at the end of the drawer
],
),
);
}
bool isListLarge() {
return controller.positions.isNotEmpty && physics.shouldAcceptUserOffset(controller.position);
}
}
Standalone code example (Update 1: Sticky LogOutButton):
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(),
drawer: MyDrawer(),
),
);
}
}
class MyDrawer extends StatefulWidget {
#override
_MyDrawerState createState() => _MyDrawerState();
}
class _MyDrawerState extends State<MyDrawer> {
int entries = 4;
#override
Widget build(BuildContext context) {
return Drawer(
child: Column(
children: <Widget>[
Flexible(
child: ListView(
shrinkWrap: true,
children: List<int>.generate(entries, (i) => i)
.map((i) => ListTile(
title: Text(i.toString()),
))
.toList(),
),
),
IconButton(
icon: Icon(Icons.exit_to_app),
onPressed: () => {setState(() => entries += 4)})
],
),
);
}
}
Standalone code example (Old: Sticking to bottom):
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(),
drawer: MyDrawer(),
),
);
}
}
class MyDrawer extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Drawer(
child: Column(
children: <Widget>[
Expanded(
child: ListView(
children: List<int>.generate(40, (i) => i + 1)
.map((i) => ListTile(
title: Text(i.toString()),
))
.toList(),
),
),
IconButton(icon: Icon(Icons.exit_to_app), onPressed: () => {})
],
),
);
}
}