How to load multiple list view inside single list view? - json

I'm working on flutter app in which I want to show feeds, I want to show 1st list(Horizontal list) with 4 workouts, 2nd list (Vertical list) with 4 posts, 3rd list (Horizontal list) with 4 coaches and 4th list again 4 posts. At the end of list there is 'Load More' button and after click on button again repeating 1st step i.e. 4 workouts, 4 Posts, 4 Coaches and 4 Posts. My question is What is the best way to display this type of view.
Video For clear my points

Here is an example of what you want to achieve:
List<List<String>> lists = [["A1","A2","A3","A4","A5"],["B1","B2","B3"],["C1","C2","C3","C4","C5"],["D1","D2","D3"]];
Widget buildCard(String text) {
return Container(
margin: EdgeInsets.all(4.0),
padding: EdgeInsets.all(40.0),
alignment: Alignment.center,
color: Colors.lightGreenAccent,
child: Text(text),
);
}
Widget buildHorizontalList(List<String> sublist) {
return SizedBox(
height: 200.0,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: sublist.length,
itemBuilder: (context, index) => buildCard("${sublist[index]}"),
),
);
}
Widget buildVerticalList(List<String> sublist) {
return ListView.builder(
shrinkWrap: true,
physics: NeverScrollableScrollPhysics(),
itemCount: sublist.length,
itemBuilder: (context, index) {
return buildCard("${sublist[index]}");
},
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: ListView.builder(
itemCount: lists.length + 1,
itemBuilder: (context, index) {
if (index <= lists.length - 1) {
return index.isEven ? buildHorizontalList(lists[index]) : buildVerticalList(lists[index]);
}
return RaisedButton(
child: Text('Load More'),
onPressed: () {
setState(() {
lists.addAll([["X1","X2","X3","X4","X5"],["Y1","Y2","Y3"]]);
});
},
);
}),
);
}
Edit: I added the Load More button functionality, basically the button just update the 'lists' variable (a list that contains all the sublists). Then the ListViews are being build according to the 'lists' content.

Can't you, instead of showing every listview within another listview, just show it all within a SingleChildScrollView, and then just add all the listviews to a row widget.
SingleChildScrollView(
child: Column(
children<widget>[
// Put listviews here.
],
),
),

Related

Filter ListView with FutureBuilder?

How can I upgrade this code into searching listview?
I try with using two lists and using where keyword but it not worked. some problem with filling data into a list, then printing the list it always shows Instance of User
class ListBuilder extends StatefulWidget {
final FetchList fetchList;
ListBuilder({required this.fetchList});
#override
_ListBuilderState createState() => _ListBuilderState();
}
class _ListBuilderState extends State<ListBuilder> {
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: widget.fetchList.getUsers(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return LoadingView();
} else {
if (snapshot.data.length > 0) {
return Column(
children: [
Padding(
padding: const EdgeInsets.all(12.0),
child: TextField(
// onChanged: onItemChanged,
// controller: _textController,
decoration: InputDecoration(
hintText: 'Search Here by EmployeeId...',
),
),
),
Expanded(
child: ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return UserListTile(user: snapshot.data[index]);
},
),
),
],
);
} else {
return EmptyView();
}
}
},
);
}
}
Here this list view build by using JSON data and using flutter FutureBuilder.
I would suggest doing such things with a proper state management. While you can certainly achieve this within the widget, it will end with a poorly designed app. Have a look at this brief tutorial on a todo list with filters using BLoC. Then there is a filtered list example which reads data from the network. I believe this makes more sense and is not so hard to learn

Flutter: How to display all columns in the same table

I am working on a test application in Dart. The application is used for displaying and inserting data into a database hosted with 000webhost.com
I am displaying my json data into a table in my app. I would like all the columns to be inside of one table. With my current code it is displaying every column inside of a brand new table
like shown here:
Below is the relevant code for my project:
class ViewData extends StatelessWidget{
final String url = 'https://fourieristic-thousa.000webhostapp.com/index.code.php?action=view';
Future<List<dynamic>> fetchData() async {
var result = await http.get(
Uri.parse(url),
);
print(json.decode(result.body));
return json.decode(result.body);
}
// First entry of each column.
String _test(dynamic test, int index){
return test[index]['testColumn'];
}
// Second entry of each column.
int _test2(dynamic test, int index){
return json.decode(test[index]['testColumn2']);
}
// Third entry of each column (Will some day be a delete function)
int _id(dynamic test, int index){
return json.decode(test[index]['ID']);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Test data table'),
),
body: Container(
child: FutureBuilder<List<dynamic>>(
future: fetchData(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if(snapshot.hasData){
return ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: DataTable(
columns: const <DataColumn>[
DataColumn(
label: Text(
'Test',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Test2',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
DataColumn(
label: Text(
'Delete',
style: TextStyle(fontStyle: FontStyle.italic),
),
),
],
rows: <DataRow>[
DataRow(
cells: <DataCell>[
DataCell(
Text(_test(snapshot.data, index).toString())
),
DataCell(
Text(_test2(snapshot.data, index).toString())
),
DataCell(
Text(_id(snapshot.data, index).toString())
)
],
),
],
),
);
}
);
} else {
return Center(child: CircularProgressIndicator());
}
},
),
),
);
}
}
I have tried looking for an answer online with no result. I have also tried rewriting my code to attempt to find anything wrong with it. I understand why the app is showing the data in individual tables, but I can not find a way to fix it.
You claim to know what the problem is so I won't go in depth, but the main issue is your ListView.builder; there is no reason to have it there. Instead, you should replace the code between if(snapshot.hasData){ and return SingleChildScrollView( with something like this:
List<DataRow> dataRows = [];
for (var index = 0; index < snapshot.data.length; index++) {
dataRows.add(
DataRow(
cells: <DataCell>[
DataCell(
Text(_test(snapshot.data, index).toString())
),
DataCell(
Text(_test2(snapshot.data, index).toString())
),
DataCell(
Text(_id(snapshot.data, index).toString())
),
],
),
);
}
and then put the dataRows variable in the rows: field of your DataTable. Your tree should end up being Scaffold -> Container -> FutureBuilder -> SingleChildScrollView -> DataTable. This way you won't be building a new table for every entry.

How to keep precedent widgets after setState

I want to create a dynamic listview of cards I create with a title and a content. I'm decoding what I receive from the two textfields of the adding page but then when a card is created, it doesn't work well. For the first card, it works perfectly, but when a second one is created, the two cards are the same. I don't really know how to keep my precedent cards while adding new one. If you have any ideas or tips please tell me. Thank you in advance! Here's my code :
class MyPage extends StatefulWidget {
#override
_MyPageState createState() => _MyPageState();
}
class _MyPageState extends State<MyPage> {
static List dreams = [];
static List contentCard = [];
String text;
String title;
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: kEdgeColor,
appBar: AppBar(
backgroundColor: kEdgeColor,
elevation: 0,
title: Text('My dreams'),
),
body: Container(
decoration: BoxDecoration(
color: Colors.black),
child: ListView.builder(
itemCount: dreams.length ,
itemBuilder: (BuildContext ctxt, int index) {
return new DreamCard(
Content: text,
title: title,
);
}
)
),
bottomNavigationBar: BottomAppBar(
color: kEdgeColor,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
FlatButton(
onPressed: (){
Navigator.popAndPushNamed(context, '/public');
},
child: Icon(Icons.public),
color: Colors.black,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
),
FlatButton(
onPressed: (){
Navigator.popAndPushNamed(context, '/');
},
child: Icon(Icons.bedtime),
color: Colors.black,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(15)),
),
],
),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
floatingActionButton: FloatingActionButton(
onPressed: () async {
final result = await Navigator.of(context).push(MaterialPageRoute(builder: (context){return WritingPage();}));
if (null != result) {
dreams.add(result);
Map<String, dynamic> resultat = jsonDecode(result);
setState(() {text = resultat['text'];
title = resultat['title'];});
}
},
child: Icon(Icons.add, size: 30,color: Colors.black,),
backgroundColor: Colors.white,
),
);
}
}
cause you're only update the title and text when press, and your DreamCard has the same title and text, since you'r not reference items in dreams list by index. so your DreamCard in list always look the same.
if (null != result) {
Map<String, dynamic> resultat = jsonDecode(result);
// use setState to update your dreams list to trigger UI change
setState(() {
dreams.add(resultat);
});
}
ListView.builder(
itemCount: dreams.length ,
itemBuilder: (BuildContext ctxt, int index) {
// access item from dreams list by index
return new DreamCard(
Content: dreams[index]['text'],
title: dreams[index]['title],
);
}
)
Your itemBuilder is not referencing index in:
child: ListView.builder(
itemCount: dreams.length ,
itemBuilder: (BuildContext ctxt, int index) {
return new DreamCard(
Content: text,
title: title,
);
}
so of course all cards will always has the same text and title as whatever is in scope. You need to put the data in dreams and reference dreams[index][?something?] to get the two values appropriate for this card.
You cannot see the correct text for the next DreamCard added because you are adding the result received from WritingPage page directly to the dreams list. You are then JSON decoding result and setting the values of variables text and title. These values of the latest WritingPage are sent to DreamCard therefore every DreamCard appears to be the same. Instead you should be JSON decoding the dreams list and using the text and title from dreams list. Please make the following changes.
return new DreamCard(
Content: jsonDecode(dreams[index])["text"],
title: jsonDecode(dreams[index])["title"],
);

Want to remove indexed item in flutter's listview

There is an order list(contains orders) which is configured with pageview builder(Horizontal scroll) and in each order page there are items in listview.builder(vertical scroll), which I am able to successfully configure dynamically.
Now every order has n number of items, and each item has an button, which calls for action successfully. Now after the successful action, I want the order item in a order for which the action was executed should be removed from the listview.builder, because it gets removed in the server backend.
And when the order has no items left, it should be removed from the pageview.builder as well, because it is also removed from the server.
the code I am using is below for the widget of pageview.builder and list.viewbuilder
FutureBuilder(
future: _future,
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.none:
return Text('none');
case ConnectionState.waiting:
return Center(child: CircularProgressIndicator());
case ConnectionState.active:
return Text('');
case ConnectionState.done:
if (snapshot.hasError) {
return Text(
'${snapshot.error}',
style: TextStyle(color: Colors.red),
);
} else {
return PageView.builder(
scrollDirection: Axis.horizontal,
itemCount: snapshot.data.content.length,// length of total orders
itemBuilder: (context, index) {
var firstdata = jsonResponse['content'];
var list = firstdata[index]['order_items'];
return Column(
children:<Widget>[
Text( firstdata[index]['order_no]),
ListView.builder(
shrinkWrap: true,
itemCount: //lenght of the items in the order to be determined,
itemBuilder: (context, index) {
return Column(
children: [
Text(list[index]['item_number']),
RaisedButton(
onPressed: (){
callaction();
},
)
],
);
},
),
])
});
}
}
})
Function called
callaction(){
print('action called on server');
var response = await http.post(url, body: data);
if (response.statusCode == 200) {
print('success');
}
}
Please guide me on how should I achieve the desired functionality. json flutter indexing flutter-listview flutter-pageview
You could pass the index of the firstdata's item to callaction(). The problem is that the second builder's index is shadowing the first, so you need to rename at least one of the two. Then you can do callaction(firstIndex) and from there, remove the correct item from firstdata.

Flutter: exclude one object from scrolling within a listview

I have a listview of objects that contains basically a form with textfields, a google maps object and then another form of checkboxes.
What I would like to do is have the google maps object not part of the scroll physics of the listview as a whole, because then you cannot actually move the map around at all.
Some code:
Constructor inside the build widget:
Flexible(
child: StreamBuilder(
stream: Firestore.instance.collection('users').document(uid).snapshots(),
builder: (BuildContext context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasData) {
return ListView.builder(
physics: ScrollPhysics(),
shrinkWrap: true,
itemCount: 1,
itemBuilder: (context, index) =>
_buildListRows(context, snapshot.data),
);
} else {
return LoadingAnimation();
}
},
),
),
The _buildListRows Widget, simplified:
Widget _buildListRows(BuildContext context, DocumentSnapshot document) {
return Container(
child: Form(
child: Column(
children: <Widget>[
Container(
child: TextFormField(),
),
Container(
child: SizedBox(
child: GoogleMap(),
),
),
Expanded(
Container(
ListView(
physics: ScrollPhysics(),
children: keys.map(key) {
return Checkbox(value: key);
}
),
),
],
),
),
);
}
So a quick recap, I need to be able to scroll the objects above and below the map, to move the whole screen up and down, but on the map itself I need to be able to control the map, so that touch actions apply to map functionality instead.
I have read a lot about this and tried some of the suggestions like having a singlechildscrollview and then listviews underneath that parent but it seems anything else I try just completely breaks the app and nothing will display at all.