Separating main screen with different ListView items - flutter

So I have this ListView where it creates a new ListTile item on click of a button (for now it is a floating action button, but it would need to be changed). Here is the code of the ListView:
body: Container(
),
),
child: BlocConsumer<FoodBloc, List<Food>>(
builder: (context, foodList) {
return ListView.separated(
itemBuilder: (BuildContext context, int index) {
print("foodList: $foodList");
Food food = foodList[index];
return Container(
color: Colors.white60,
child: ListTile(
trailing: Container(
padding: EdgeInsets.only(top: 15.0),
child: IconButton(
icon: Icon(Icons.add),
onPressed: () => null,
),
),
title: Text(food.name, style: TextStyle(fontSize: 30)),
subtitle: Text(
"Calories: ${food.calories} ${food.price} din\nVegan: ${food.isVegan}",
style: TextStyle(fontSize: 20),
),
onTap: () => showFoodDialog(context, food, index)),
);
},
itemCount: foodList.length,
separatorBuilder: (BuildContext context, int index) =>
Divider(color: Colors.black),
);
},
listener: (BuildContext context, foodList) {},
),
),
Here is the floating action button below that creates a new ListTile inside. I would want to have this button functionality besides every type of food like in the image example instead of floating action button (that's not a problem, the layout is):
floatingActionButton: FloatingActionButton(
tooltip: 'Add Food',
child: Icon(Icons.add),
onPressed: () => Navigator.push(context,
MaterialPageRoute(builder: (BuildContext context) => FoodForm())),
),
What I would need to do is have the same functionality, but separate the main screen with different types of food (like in the example image). They would all need to be infinitely tileable (to automatically scroll down depending on how much items there are) and would have icon button besides the type (ie drinks) that would add the ListTile to that Column. Here is a rough example of what I have and what I need.
Here is the 'Submit' button that puts the item on the ListView builder in a ListTile, not sure if anything should be changed there:
RaisedButton(
child: Text(
'Submit',
style: TextStyle(color: Colors.blue, fontSize: 16),
),
onPressed: () {
if (!_formKey.currentState.validate()) {
return;
}
_formKey.currentState.save();
Food food = Food(
name: _name,
calories: _calories,
isVegan: _isVegan,
//new var
price: _price,
//added description
description: _description,
);
DatabaseProvider.db.insert(food).then(
(storedFood) =>
BlocProvider.of<FoodBloc>(context).add(
AddFood(storedFood),
),
);

Related

Flutter UI Create menu with function after click icon more

Halo,
First, I wanna show you my current UI :
And here's the code for red circle function :
InkWell(
onTap: null,
child: Icon(Icons.more_horiz,
size: 18,
color: Color.fromRGBO(0, 0, 0, 0.25),
),
),
What action I needed is to show pop-up menu like this after click the icon, for example :
I need that to create edit and delete with function to navigate to another page, and need to know how to control menu position.
I already check on pub.dev, but it didn't resolve my problem.
Can anyone give me an advice?
Try this code :
the package is here : https://pub.dev/packages/pull_down_button
PullDownButton(
itemBuilder: (context) => [
PullDownMenuItem(
title: 'Menu item',
onTap: () => action(),
),
const PullDownMenuDivider(),
PullDownMenuItem(
title: 'Menu item 2',
onTap: () => action2(),
),
],
position: PullDownMenuPosition.under,
buttonBuilder: (context, showMenu) => CupertinoButton(
onPressed: showMenu,
padding: EdgeInsets.zero,
child: const Icon(CupertinoIcons.ellipsis_circle),
),
);
result :
You can try using PopupMenuButton you can find here an example
Try below code hope its help to you. and used PopupMenuButton
Declare Key Variable:
final GlobalKey menuKey = GlobalKey();
Widget:
InkWell(
onTap: () {
dynamic state = menuKey.currentState;
state.showButtonMenu();
},
child: PopupMenuButton(
key: menuKey,
itemBuilder: (_) => const <PopupMenuItem<String>>[
PopupMenuItem<String>(
child: Text('Show Test'),
value: 'Test',
),
PopupMenuItem<String>(
child: Text('Edit Test Solution'),
value: 'Edit',
),
],
onSelected: (_) {},
),
),
Result->

How to show insert data into list view builder without reload application in flutter

I have created a sqlite crud application from flutter. my app data insert into the table successfully. but when i show that inserted date from listview need to reload app.in my app data insert from a separate screen. data have shown on home screen. i want show data without reload app in listview how can I slove my problem?
Here is my app code. this is my home screen. this screen show data from listview.
FutureBuilder<List<Student>>(
future: DatabaseHelper.instance.getStudentDetails(),
builder: (BuildContext context,
AsyncSnapshot<List<Student>> snapshot) {
if (!snapshot.hasData) {
return Center(child: Text('Loading...'));
}
return snapshot.data!.isEmpty
? Center(child: Text('No Student Details in List.'))
: ListView(
children: snapshot.data!.map((student) {
return Center(
child: Card(
color: selectedId == student.id
? Colors.white70
: Colors.white,
child: ListTile(
title: Text(
'Student Name : ${student.name}'),
subtitle:
Text('Course : ${student.course}'),
onTap: () {},
onLongPress: () {
setState(() {
DatabaseHelper.instance
.remove(student.id!);
});
},
),
),
);
}).toList(),
);
}),
This is my second screen.this screen I adding data insert into sqlite table.when I click floating action button I want to show insert data in home screen list view without reload.
Column(
children: [
SizedBox(
height: 10.0,
),
Text(
'Enter Student Details',
style: TextStyle(fontSize: 20.0, fontWeight: FontWeight.bold),
),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Divider(color: Colors.black),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
decoration: InputDecoration(
label: Text('Enter Name :'),
),
controller: nameController,
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
decoration: InputDecoration(
label: Text('Enter Course :'),
),
controller: courseController,
),
),
],
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.save),
onPressed: () async {
await DatabaseHelper.instance.add(
Student(name: nameController.text, course: courseController.text),
);
setState(() {
nameController.clear();
courseController.clear();
selectedId = null;
});
},
),
future: DatabaseHelper.instance.getStudentDetails(), will get recall the api on every setState(build).
To avoid recalling the api, create a state variable for this future on state class (outside the build method).
late final future = DatabaseHelper.instance.getStudentDetails();
and use it on FutureBuilder
FutureBuilder<List<Student>>(
future: future,
builder: (BuildContext context,
You can check Fixing a common FutureBuilder and StreamBuilder problem by
Randal L. Schwartz.

How to align the text within ListTile?

Is there any other way for me to align the text within the leading and title of a ListTile without using the Row widget? The data was fetched from Firebase and then being viewed using Listview. Builder.
FutureBuilder(
future: fetchData(),
builder: (context, snapshot) {
if (snapshot.hasData) {
List<taskData> result = snapshot.data as List<taskData>;
return ListView.builder(
scrollDirection: Axis.vertical,
itemCount: result.length,
itemBuilder: (BuildContext context, int i) {
DateTime updateDate = DateTime.fromMillisecondsSinceEpoch(result[i].date);
String formDate = DateFormat('yMMMd').format(updateDate);
return GestureDetector(
onTap: () {
NavigationController(context, 'Edit', 'Title',
result[i].task, result[i].id, updateDate);
},
child: Card(
child: ListTile(
leading: Text(formDate, style: TextStyle(fontFamily: 'ProximaNova', fontSize: 16),),
title: Text('${result[i].task}',style: TextStyle(fontFamily: 'ProximaNova',fontSize: 18),),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () {
id = result[i].id;
showDialog<void>(
context: context, builder: (context) => dialog);
},
),
),
),
);
});
} else if (snapshot.hasError) {
print('${snapshot.error}');
return Text(
"",
style: TextStyle(fontSize: 20),
);
}
// By default, show a loading spinner.
return Center(
child: Container(
margin: EdgeInsets.symmetric(vertical: 100.0),
child: CircularProgressIndicator(),
));
},
),
Here is the picture for reference ('title' is not aligned with 'leading' and 'trailing'):
It is working for you
ListTile(
leading: Text('2021-04-27'),
title: Text('Lion', textAlign: TextAlign.center,),
trailing: IconButton(
icon: Icon(Icons.delete),
onPressed: () {},
),
),
Sorry if I'm not solving the problem asked but as a suggestion how about wrapping it in a Row Widget instead of a List Tile where you center align it?
first of all i believe you leading is not aligned with title and trailing, i do not know due to what reason this is happening from your code. solution might be Put your both text in title with + operator. or in leading whichever helps your problem get solved.

Flutter Show Data Once in ListView

I have listview in my app and in this listView I pull the book titles with API. Book titles are coming up without any problems. But if I press the button more than once, the titles increase as much as I press the button
Here is my code sample
_showData
? Container(
height: MediaQuery.of(context).size.height / 2,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Column(
children: [
IconButton(
icon: Icon(Icons.close),
onPressed: () {
Navigator.pushNamed(
context, CountryScreen.routeName);
}),
Center(
child: Text(
'Please Select Book',
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 24),
),
),
],
),
Expanded(
child: ListView.builder(
itemCount: bookList.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
onTap: () {
Navigator.pushNamed(
context, MainScreen.routeName);
},
title: Text(bookList[index]),
);
),
],
),
),
)
: SizedBox()
I'm calling my data here,I'm calling in the button
else {
_showData = !_showData;
books.forEach((element) {
bookList.add(element.companyName);
book.setStringList(
'bookName', bookList);
});
}
To illustrate with a small example When I click once on the button I call the data
but if I click twice I see this (the more I click the more it gets), any idea?
The build() method is called whenever there is a change to redraw in the UI. But at that time your bookList state will not be reset.
I will give a trick code to fix this problem:
bookList = [];
books.forEach((element) {
bookList.add(element.companyName);
book.setStringList('bookName', bookList);
});

How to pass a variable reference between different routes?

Im writing a simple gamebook game in flutter with menu, game and options route. In option route there is button that on pressed should delete all saved games.
Right at this moment Im loading saved games on application launch from SharedPreferences. Right after loading them I set up boolean _savedGame that im using in 'Continue' button in menu route and 'Delete saved games' button in options route to activate or deactivate them. The whole problem is - i dont know how to change variables in menu route from option route. When im creating option route I give it _savedGame so that it knows if it should render active or deactivated button.
PS. Yes, I know that right now im sending option route a copy of _savedGame variable.
Menu route option page button.
RaisedButton(
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) => OptionsPage(_savedGame),
),
),
Option page
class OptionsPageState extends State<OptionsPage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(
"Options",
style: TextStyle(color: Colors.white),
),
backgroundColor: Colors.blueGrey[900],
),
body: Container(
alignment: Alignment.center,
color: Colors.cyan,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child:
Text('Delete saved games', style: TextStyle(fontSize: 40)),
onPressed:
widget.isGameSaved ? () => _showWarning(context) : null,
),
const SizedBox(height: 30),
RaisedButton(
child: Text('Back', style: TextStyle(fontSize: 40)),
onPressed: () {
Navigator.pop(context);
},
),
])),
),
);
}
Future<void> _showWarning(BuildContext context) {
return showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: Text('Are you sure you want to delete saved game?'),
actions: <Widget>[
FlatButton(
child: Text('No'),
onPressed: () {
Navigator.of(context).pop();
},
),
FlatButton(
child: Text('Yes'),
onPressed: () {
saveGame('empty');
Navigator.of(context).pop();
setState(() {
widget.isGameSaved = false;
});
},
),
],
);
},
);
}
}
How do I "setState" for variables in different routes?
What you could do is have an InheritedWidget (call it say GameStateWidget) above your Navigator (or MaterialApp if you're using its navigator). In the InheritedWidget have a ValueNotifier, say savedGame that has the value you want to share.
Then in the route where you need to set the value
GameStateWidget.of(context).savedGame.value = ...
And in the route where you need the value
ValueListenableBuilder(
valueListenable: GameStateWidget.of(context).savedGame,
builder: (context, savedGameValue, child) => ...
)