Synchronization of list view and detail view - list

I have an app with simple functionality. After authentication user see the page with ListView widget which is populated with help of StreamBuilder widget and BLoC. Click on ListView row opens details page with set of detail widgets (TextField. Now I need to change my GUI design for tables. As we have more space I decided to display details near the list view, i.e. when user clicks on ListView item no new page opened but details are displayed on the right side of ListView. I need the idea how to synchronize the detail view widget with selected item in list view widget. I figured out that I can use somehow ValueNotifier/ValueListenableBuilder but I can't gather my thoughts together. I need some ideas, please.

please use this package responsive_scaffold https://pub.dev/packages/responsive_scaffold
On mobile it shows a list and pushes to details and on tablet it shows the List and the selected item.
example code
import 'package:flutter/material.dart';
import 'package:responsive_scaffold/responsive_scaffold.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
var _scaffoldKey = new GlobalKey<ScaffoldState>();
#override
Widget build(BuildContext context) {
return MaterialApp(
home: ResponsiveListScaffold.builder(
scaffoldKey: _scaffoldKey,
detailBuilder: (BuildContext context, int index, bool tablet) {
return DetailsScreen(
// appBar: AppBar(
// elevation: 0.0,
// title: Text("Details"),
// actions: [
// IconButton(
// icon: Icon(Icons.share),
// onPressed: () {},
// ),
// IconButton(
// icon: Icon(Icons.delete),
// onPressed: () {
// if (!tablet) Navigator.of(context).pop();
// },
// ),
// ],
// ),
body: Scaffold(
appBar: AppBar(
elevation: 0.0,
title: Text("Details"),
automaticallyImplyLeading: !tablet,
actions: [
IconButton(
icon: Icon(Icons.share),
onPressed: () {},
),
IconButton(
icon: Icon(Icons.delete),
onPressed: () {
if (!tablet) Navigator.of(context).pop();
},
),
],
),
bottomNavigationBar: BottomAppBar(
elevation: 0.0,
child: Container(
child: IconButton(
icon: Icon(Icons.share),
onPressed: () {},
),
),
),
body: Container(
child: Center(
child: Text("Item: $index"),
),
),
),
);
},
nullItems: Center(child: CircularProgressIndicator()),
emptyItems: Center(child: Text("No Items Found")),
slivers: <Widget>[
SliverAppBar(
title: Text("App Bar"),
),
],
itemCount: 100,
itemBuilder: (BuildContext context, int index) {
return ListTile(
leading: Text(index.toString()),
);
},
bottomNavigationBar: BottomAppBar(
elevation: 0.0,
child: Container(
child: IconButton(
icon: Icon(Icons.share),
onPressed: () {},
),
),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () {
_scaffoldKey.currentState.showSnackBar(SnackBar(
content: Text("Snackbar!"),
));
},
),
),
);
}
}

Related

List data Disappears after pressing back Flutter

Whenever I add an item to my least it adds to the list at the current state but when I reopen after pop context the item is no more there
*How can I have the items in list permanently *enter image description hereenter image description hereenter image description hereenter image description hereenter image description here
class Prabesh extends StatefulWidget {
#override
_PrabeshState createState() => _PrabeshState();
}
class _PrabeshState extends State<Prabesh> {
final List users = [
'Ram',
'Shyam',
'Hari',
'Paudel',
'Pandey',
'Sashwat',
'Kismat',
];
// ondlt(Key key) {
// for (int i = 0; i <= users.length; i++) {
// var a = users.elementAt(i);
// if (key == a.key) {
// users.removeAt(i);
// }
// }
// }
void onClk() {
myDialog(BuildContext, context);
}
final myUser = TextEditingController();
myDialog(BuildContext, context) {
showDialog(
barrierDismissible: false,
context: context,
builder: (context) {
return AlertDialog(
title: Text('Add a user'),
content: TextFormField(
controller: myUser,
maxLength: 20,
decoration: InputDecoration(
hintText: 'Enter Username',
),
),
actions: [
ElevatedButton(
onPressed: () => Navigator.pop(context),
child: Text('Cancel')),
ElevatedButton(
onPressed: () {
setState(() {
if (myUser.text.isEmpty) {
return Navigator.pop(context);
} else {
users.add(myUser.text);
return Navigator.pop(context);
}
});
},
child: Text('Add'),
),
],
);
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Prabesh'),
leading: BackButton(
onPressed: () => Navigator.pop(context),
),
),
body: ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
return Card(
elevation: 10,
child: ListTile(
// key: Key(users[index]),
//onLongPress: () => ondlt(key),
onTap: () {},
title: Text(users[index]),
trailing: Icon(Icons.menu),
leading: CircleAvatar(
child: Text(users[index].substring(0, 1)),
),
),
);
},
),
floatingActionButton: FloatingActionButton(
onPressed: () => onClk(),
child: Icon(Icons.add),
),
),
);
}
}
You must save your data locally or on an online database.
For saving data on mobile storage you can use this package.
But for saving data on an online database you can use Firebase or you must develop a web server.

When adding item to list in flutter, the item does not save in that list

I have a list of users which show in a dropdown in a form which is then submitted, the list is empty, I have made a function which allows users to type a "name" into a TextFormField and it then adds that name to the list, it then appears on the dropdown, but when the page is reloaded the list item has gone.
example:
void savePerson() {
String newperson = _newPersonController.text;
_persons.add(newperson);
}
The function to save string to list
List<String> _persons = [
];
The List
TextFormField(
controller: _newPersonController,
decoration: InputDecoration(
hintText: 'Add New Person',
prefixIcon: Icon(
Icons.local_hospital,
size: 30,
),
fillColor: Colors.white,
filled: true,
contentPadding: EdgeInsets.all(15),
)),
The TextFormField where the user inserts the name to be added
FlatButton(
onPressed: () {
savePerson();
setState(() {
_newPersonController.clear();
});
},
child: Text('Add Person'))
Button code
Just to be clear, it ADDS it to the list/dropdown - that works, but my list doesn't seem to be able to save info to it.
I'm fairly new to flutter - sorry for anything obvious.
The problem maybe the logic of the dropdown, and add the setState() when you add the item to the people list
I use this code:
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final TextEditingController _newPersonController =
new TextEditingController();
List<String> _persons = [];
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Material App',
home: Scaffold(
appBar: AppBar(
title: Text('Material App Bar'),
),
body: Center(
child: Column(
children: <Widget>[
DropdownButton(
items: List.generate(
_persons.length,
(i) => DropdownMenuItem(
child: Text(_persons[i]),
)),
onChanged: (_) {}),
TextFormField(
controller: _newPersonController,
decoration: InputDecoration(
hintText: 'Add New Person',
prefixIcon: Icon(
Icons.local_hospital,
size: 30,
),
fillColor: Colors.white,
filled: true,
contentPadding: EdgeInsets.all(15),
)),
FlatButton(
onPressed: () {
savePerson();
setState(() {
_newPersonController.clear();
});
},
child: Text('Add Person'))
],
),
),
),
);
}
void savePerson() {
String newperson = _newPersonController.text;
setState(() {
_persons.add(newperson);
});
}
}
Probably can help you

I want to make categories page for the shopping application in flutter?

I have made the categories page for my project by making categories page and the data which I am going to display in the category page is imported from data.dart file and I have to use the visible widget but I am facing an error using the code.
The code of data.dart is below:
List<Category> categories = [
Category(
name: 'Accessories',
icon: FontAwesomeIcons.tshirt,
),
Category(
name: 'AutoMobiles',
icon: FontAwesomeIcons.car,
),
Category(
name: 'Beauty and Health',
icon: FontAwesomeIcons.hatCowboy,
),
Category(
name: 'Business & Industrial',
icon: FontAwesomeIcons.cashRegister,
),
Category(
name: 'Book and Learning',
icon: FontAwesomeIcons.book,
),
Category(
name: 'Computer and Peripherals ',
icon: FontAwesomeIcons.laptop,
),
Category(
name: 'Electronics ',
icon: FontAwesomeIcons.tv,
),
and the code for making the categories page is given below:
class CategoryPage extends StatefulWidget {
static String id = 'categoryPage';
#override
_CategoryPageState createState() => _CategoryPageState();
}
class _CategoryPageState extends State<CategoryPage> {
bool isClicked = false;
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: Column(
children: [
Text(
'All Categories',
),
Expanded(
child: ListView.builder(
scrollDirection: Axis.vertical,
itemCount: categories.length,
itemBuilder: (context, index) {
return Column(
children: <Widget>[
Expanded(
child: ListTile(
leading: GestureDetector(
onTap: () {
setState(() {
isClicked = !isClicked;
});
},
child: Icon(
categories[index].icon,
),
),
title: Visibility(
visible: isClicked,
child: Text(
categories[index].name,
),
),
),
),
Expanded(
child: ListView.builder(
itemCount: 1,
itemBuilder: (context, index) {
return ListTile(
leading: Text('Hello!'),
);
}),
)
],
);
},
),
),
],
),
// bottomNavigationBar: NavBar(),
),
);
}
}
I have researched well but am unable to solve the problem. How can I get the desirable output and the image file which I was trying to make in the categories page like the image attached below?
A Column will always try to shrinkWrap it's children, using Expanded means the child is supposed to occupy the entire height, these two are mutually exclusive.
A better way to use a Single Scroll View without all those Expanded widgets would be this.
class CategoryPage extends StatefulWidget {
static String id = 'categoryPage';
#override
_CategoryPageState createState() => _CategoryPageState();
}
class _CategoryPageState extends State<CategoryPage> {
bool isClicked = false;
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
Text(
'All Categories',
),
ListView.builder(
physics: NeverScrollableScrollPhysics(),
shrinkWrap: true,
itemCount: categories.length,
itemBuilder: (context, index) {
return Column(
children: <Widget>[
Expanded(
child: ListTile(
leading: GestureDetector(
onTap: () {
setState(() {
isClicked = !isClicked;
});
},
child: Icon(
categories[index].icon,
),
),
title: Visibility(
visible: isClicked,
child: Text(
categories[index].name,
),
),
),
),
Expanded(
child: ListView.builder(
itemCount: 1,
itemBuilder: (context, index) {
return ListTile(
leading: Text('Hello!'),
);
}),
),
],
);
},
),
],
),
),
// bottomNavigationBar: NavBar(),
),
);
}
}
If the Error is caused by the Inner ListView, you can apply the same logic of SingleChildScrollView()

Dart, Flutter List onTap to get index of taped item

i created a search delegate class and what i want sounds logically simple but i cant wrap my head around it as i am new programming
i want to get the text or maybe i should say string of the text in the listTile i tap on ,
then pass that text to the showResult of search delegate and view it in a text widget
... here is my code
import 'package:flutter/material.dart';
import 'package:schooler/style/const.dart';
//follow steps 1 - 3
class DataSearch extends SearchDelegate<String> {
final List<String> languages = [//3.here is my list
'dart',
'Csharp',
'Java',
'JavaScript',
'C++',
'go ',
'python',
'php'
];
final List<String> recentSearch = [
'go ',
'python',
'php',
];
#override
List<Widget> buildActions(BuildContext context) {
return [
IconButton(
icon: Icon(Icons.clear),
onPressed: () {
query = '';
},
)
];
}
#override
Widget buildLeading(BuildContext context) {
return IconButton(
icon: AnimatedIcon(
icon: AnimatedIcons.menu_arrow,
progress: transitionAnimation,
),
onPressed: () {
close(context, null);
},
);
}
#override
Widget buildResults(BuildContext context) {
return Scaffold(
body: ListView(
physics: BouncingScrollPhysics(),
children: <Widget>[
Row(
children: <Widget>[
CircleAvatar(),
Text(languages[0].substring(query.length)),//2.i want to return the gotten index here
],
),
],
),
);
}
#override
Widget buildSuggestions(BuildContext context) {
final suggestionList = query.isEmpty
? recentSearch
: languages.where((element) => element.startsWith(query)).toList();
return ListView.builder(
physics: BouncingScrollPhysics(),
itemBuilder: (context, index) => ListTile(
onTap: () {
showResults(context); //1.when i tap the item on the listTile i want it to get the index of the taped item
},
leading: query.isEmpty
? Icon(
Icons.history,
)
: Icon(Icons.search),
title: RichText(
text: TextSpan(
text: suggestionList[index].substring(
0,
query.length,
),
style: TextStyle(
color: kBlackColor,
fontWeight: kBold,
),
children: [
TextSpan(
text: suggestionList[index].substring(query.length),
style: TextStyle(color: kGreyColor),
),
],
),
),
),
itemCount: suggestionList.length,
);
}
}
here if i tap on 'go' it should get get the text and pass it to the showResult
here is my show result ..but i just hard coded my 'list[0]index in there' i guess what i am trying to say is get the text from the item i taped and show it here
First lets fix your itemBuilder in your ListView so it indexes each element and then add that index into your showResults() function call so you have access to it:
ListView.builder(
physics: BouncingScrollPhysics(),
itemBuilder: (context, index) => ListTile( // Add index here to pass the index to the builder.
onTap: () {
showResults(context, index); // Add the index to function call
},
Just be sure your showResults() function is modified to accept an int index parameter, and while I dont see that function, I am assuming it calls buildResults() at some point which needs to be modified to accept an index:
#override
Widget buildResults(BuildContext context, int index) {
return Scaffold(
body: ListView(
physics: BouncingScrollPhysics(),
children: <Widget>[
Row(
children: <Widget>[
CircleAvatar(),
Text(languages[index].substring(query.length)),// Use the index here to return the desired text
],
),
],
),
);
}

Flutter List, detail page and todo

I have a page with a list and a bar that reaches a detail page.
I would like to add a pop on the detail page to retrieve an item and save it to a todo page but I have a problem with my detail page.
With a Stateless, I have no worries but, if I'm not mistaken, I need a Stateful to add a Future, showDialog .. but, I have problems with my indexes... and there, I'm lost ...
Can someone give me a track or an explanation?
Thank you
home.dart
import 'dart:core';
import 'package:flutter/material.dart';
import 'package:test_todo_list/DataList.dart';
import 'package:test_todo_list/detail.dart';
class Home extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Liste Items'),
actions: <Widget>[
IconButton(icon: Icon(Icons.search),
onPressed: () {
showSearch(context: context, delegate: DataSearch(listWords));
})
],
),
body: ListView.separated(
itemCount: listWords.length,
separatorBuilder: (BuildContext context, int i) =>
Divider(color: Colors.grey),
itemBuilder: (context, i) {
return ListTile(
onTap: () {
Navigator.push(
context,MaterialPageRoute(
builder: (context) => Detail(listWordsDetail: listWords[i]),
),
);
},
title: RichText(
textAlign:TextAlign.left,
text: TextSpan(
children:<TextSpan>[
TextSpan(
text:listWords[i].titlelist,
style:Theme.of(context).textTheme.title.merge(TextStyle(color: Colors.blueGrey)),
),
]
)
),
subtitle: Text(listWords[i].definitionlist,
style: Theme.of(context).textTheme.subtitle.merge(
TextStyle(fontStyle: FontStyle.italic, color: Colors.grey)),
),
trailing: Icon(Icons.arrow_forward_ios, color: Colors.grey),
);
},
),
);
}
}
class DataSearch extends SearchDelegate<String> {
final List<ListWords> listWords;
DataSearch(this.listWords);
#override
List<Widget> buildActions(BuildContext context) {
//Actions for app bar
return [IconButton(icon: Icon(Icons.clear), onPressed: () {
query = '';
})];
}
#override
Widget buildLeading(BuildContext context) {
//leading icon on the left of the app bar
return IconButton(
icon: AnimatedIcon(icon: AnimatedIcons.menu_arrow,
progress: transitionAnimation,
),
onPressed: () {
close(context, null);
});
}
#override
Widget buildResults(BuildContext context) {
// show some result based on the selection
final suggestionList = listWords;
return ListView.builder(itemBuilder: (context, index) => ListTile(
title: Text(listWords[index].titlelist),
subtitle: Text(listWords[index].definitionlist),
),
itemCount: suggestionList.length,
);
}
#override
Widget buildSuggestions(BuildContext context) {
// show when someone searches for something
final suggestionList = query.isEmpty
? listWords
: listWords.where((p) => p.titlelist.contains(RegExp(query, caseSensitive: false))).toList();
return ListView.builder(itemBuilder: (context, index) => ListTile(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Detail(listWordsDetail: suggestionList[index]),
),
);
},
trailing: Icon(Icons.remove_red_eye),
title: RichText(
text: TextSpan(
text: suggestionList[index].titlelist.substring(0, query.length),
style: TextStyle(
color: Colors.red, fontWeight: FontWeight.bold),
children: [
TextSpan(
text: suggestionList[index].titlelist.substring(query.length),
style: TextStyle(color: Colors.grey)),
]),
),
),
itemCount: suggestionList.length,
);
}
}
detail.dart
import 'package:flutter/material.dart';
import 'package:test_todo_list/DataList.dart';
class Detail extends StatefulWidget {
Detail({Key key, #required this.listWordsDetail}) : super(key: key);
final ListWords listWordsDetail;
#override
_DetailState createState() => _DetailState();
}
class _DetailState extends State<Detail> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
brightness: Brightness.dark,
title: const Text('Détails', style: TextStyle(color: Colors.white)),
iconTheme: IconThemeData(color: Colors.white),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(listWordsDetail.titlelist +' (on detail page)',
style:Theme.of(context).textTheme.title.merge(TextStyle(color: Colors.blueGrey)),
),
Text(listWordsDetail.definitionlist,
style: Theme.of(context).textTheme.subtitle.merge(
TextStyle(fontStyle: FontStyle.italic, color: Colors.grey)),
),
Container(
padding: EdgeInsets.all(40.0),
child: GestureDetector(
onTap: () {
},
child: Icon(Icons.add_shopping_cart),
),
)
],
),
)
);
}
}
DataList.dart
List<ListWords> listWords = [
ListWords('oneWord', 'OneWord definition'),
ListWords('twoWord', 'TwoWord definition.'),
ListWords('TreeWord', 'TreeWord definition'),
];
class ListWords {
String titlelist;
String definitionlist;
ListWords(String titlelist, String definitionlist) {
this.titlelist = titlelist;
this.definitionlist = definitionlist;
}
}
After searching on the web, by chance, I found this solution that I can not explain but it's working...
import 'package:flutter/material.dart';
import 'package:test_todo_list/DataList.dart';
import 'package:test_todo_list/todo_list.dart';
class Detail extends StatefulWidget {
const Detail({Key key, this.listWordsDetail}) : super (key: key);
final ListWords listWordsDetail;
#override
_DetailState createState() => _DetailState();
}
class _DetailState extends State<Detail> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
brightness: Brightness.dark,
title: const Text('Détails', style: TextStyle(color: Colors.white)),
iconTheme: IconThemeData(color: Colors.white),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(widget.listWordsDetail.titlelist),
Text(widget.listWordsDetail.definitionlist),
Container(
padding: EdgeInsets.all(40.0),
child: GestureDetector(
onTap: () {
//open Dialog addTodoList()
},
child: Icon(Icons.add_shopping_cart),
),
)
],
),
)
);
}
Future<Null> addTodoList() async {
showDialog(context: context);
//... à construire
}
}