I used to use RecyclerView in AS but I have recently started learning Flutter.
I've been searching around and I can't seem to find a cohesive document/reference/example to allow an array List to appear in GridView.
List<Test> fbToJson(gdata) {
var tojson = json.decode(gdata).cast<Map<String, dynamic>>();
return tojson.map<Test>((json) => Test.fromJson(json)).toList();
}
class Test {
String imageUrl;
String name;
Test({this.imageUrl,this.name});
factory Test.fromJson(Map<String, dynamic> json) {
return Test(
imageUrl: json['imageUrl'] as String,
name: json['name'] as String
);
}
}
I was already able to pass the above list array to another activity class via Navigator.
My confusion is since this is a list array, I need to iterate through it to show the listed values eg.
for(var i in fbdata){
var myname = i.name;
}
I can't find any doc/resource to help show how to integrate this to a gridview if I wish to show both name and urlimage.
Thanks in advance.
Use GridView.builder
GridView.builder(
itemCount: fbdata.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 3 / 2,
crossAxisSpacing: 10,
mainAxisSpacing: 10),
itemBuilder: (ctx, index) {
return Column(
children: <Widget>[
Text(fbdata[index].name),
Text(fbdata[index].imageUrl),
],
);
})
Related
I'm a newbie Flutter programmer.
Im trying to make a generic grid widget that let me pass an object and create columns and rows dynamically.
I've made it work with an specific object but what i need is to read the names of attributes of an object to dynamically create grid column names and values so i can use the same grid for client or articles or everything.
For example i have a class for clients
class Client {
int id;
String name;
String mail;
Client({required this.id, required this.name, required this.mail});
}
then in my code retrieve a list of clients and pass that to the grid widget as List.
I just need to know how to loop the object recieved to:
get the list of fields names (id, name, mail)
then get its value for example something like
var field_name = element;
obj.field_name.value;
Hope you can understand what im trying to do.
Thank you in advance.
you can try this code
FutureBuilder<List<Client>>(
future: // your future method which return the List<Client>,
builder: (context, snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data!.length,
itemBuilder: (context, index) {
final client= snapshot.data![index];
return ListTile(
title: Text(client.name),
leading: CircleAvatar(
child: Text(client.id),
),
subtitle: Text(client.email),
);
},
);
} else if (snapshot.hasError) {
return Center(
child: Text(snapshot.error.toString()),
);
}
return Center(
child: CircularProgressIndicator(),
);
},
},),
let me know if this is working for you.
Say you are getting List of Client Object and Class looks like this
class Client {
int id;
String name;
String mail;
Client({required this.id, required this.name, required this.mail});
}
Now if your question is how can i differentiate some Client from the list and have a separate Grid widget for them?
If yes, lets take example with above given class
We have Client with category, Design, Development etc.
We can simply have a another variable in class such as
class Client {
int id;
String name;
String mail;
//type variable to differentiate , could be String or enum if you know exactly
String type;
Client({required this.id, required this.name, required this.mail});
}
and
GridView.builder(
itemCount: images.length,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 4.0,
mainAxisSpacing: 4.0
),
itemBuilder: (BuildContext context, int index){
Client item = Clients[index];
if(item.type == 'Design')
{
// display designClient item
return DesignGrid();
}
if(item.type == 'Development')
{
// display developmentType item
return DevelopmentGrid();
}
}
)
i'm trying to fetch a list of sub categories based on category id, for example:
Category A has 3 sub categories: A1 - A2 - A3
My backend works fine, I pass the category_id to the function and it returns me a list of sub categories having the category_id.
Since i'm new to getx, I tried passing the category_id as a route parameter but i'm not able to show the list of sub categories. In fact I didn't get how to pass the category_id while in the UI.
Here is my repo:
Future<Response> getSubCategoriesListByCategory(int categ_id) async {
return await apiClient.getData('shop/category/$categ_id');
}
Here is my controller:
List<dynamic> _subCategoriesListByCategory = [];
List<dynamic> get subCategoriesListByCategory => _subCategoriesListByCategory;
bool _isLoaded = false;
bool get isLoaded => _isLoaded;
Future<void> getSubCategoriesByCategoryId(int cat_id) async {
Response response =
await subCategoriesRepo.getSubCategoriesListByCategory(cat_id);
if (response.statusCode == 200) {
_subCategoriesListByCategory = [];
_subCategoriesListByCategory.addAll(response.body);
_isLoaded = true;
//print(categoriesList);
update(); // = setState();
} else {}
}
Here is my RouteHelper:
GetPage(
name: subCategory,
page: () {
var catId = Get.parameters['catId'];
return SubCategoriesPage(catId: int.parse(catId!));
},
transition: Transition.fadeIn),
And here is my UI:
GetBuilder<SubCategoriesController>(builder: (subCategories) {
return GridView.count(
crossAxisCount: 2,
shrinkWrap: true,
physics: ScrollPhysics(),
mainAxisSpacing: 16,
crossAxisSpacing: 16,
childAspectRatio: 90 / 100,
padding: EdgeInsets.all(16),
children: List.generate(
subCategories.subCategoriesListByCategory.length, (index) {
return _buildSingleSubCategory(
index,
SubCategoryModel.fromJson(
subCategories.subCategoriesListByCategory[index]));
}),
);
})
Code from home page where i'm passing the category_id:
onTap: () {
Get.toNamed(RouteHelper.getSubCategory(category.id));
},
I'm able to print the clicked category's id in the subs page which means it's passed correctly, also i'm getting GOING TO ROUTE /sub-category?catId=3
Noting that i'm priting the specific category_id correctly in the sub categories page, I couldn't fetch the specific data related to them. Any suggestion on how to solve this?
I'm not sure if this helps you since I haven't seen your full code, but I'm guessing you want to add this as parameter to your GetBuilder
initState: (state) => state.controller?.getSubCategoriesByCategoryId(widget.cat_id),
Solved it by adding: Get.find<SubCategoriesController().getSubCategories(widget.catId); inside the GetBuilder()
I have a list of several points of service in a List.
Within the PointsOfServices there is another object named Orders. How do i go about getting access to the Orders object to use it's data alongside the PointsOfService data?
Thanks
Edit: I want to be able to use this data to produce a GridView that will enable me to display both data from PointOfServices and Orders.
Will i be able to use a Future for this and FutureBuilder when creating the GridView?
You can directly access it using the index
print(mainList[0].orders[0].id);
Will print the first pointOfService's first order's Id
Note: here mainList is the name of the list that contains all pointOfService and i assumed that you have id in each order
Your question isn't clear as of what you want to exactly achieve, but to access list inside list , you can refer this ,
class PointOfService {
final String name;
final List<Order> orders;
PointOfService({this.name, this.orders});
}
class Order {
final String name;
Order({this.name});
}
void main() {
List<PointOfService> pointofServices = [
PointOfService(
name: "PointOfService 1",
orders: [
Order(name: "Order 1"),
Order(name: "Order 2"),
]),
PointOfService(
name: "PointOfService 2",
orders: [
Order(name: "Order 3"),
Order(name: "Order 4"),
])
];
for (var pointOfService in pointofServices) {
print("PointOfService name: ${pointOfService.name}");
for (var order in pointOfService.orders) {
print("Order name: ${order.name}");
}
}
}
This will output
PointOfService name: PointOfService 1
Order name: Order 1
Order name: Order 2
PointOfService name: PointOfService 2
Order name: Order 3
Order name: Order 4
Edit
For GridView you can do something like:
FutureBuilder<List<PointOfService>>(
future: < Your future here >
builder: (context, snapshot) {
if (snapshot.hasData) {
return GridView.builder(
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 200,
childAspectRatio: 3 / 2,
crossAxisSpacing: 20,
mainAxisSpacing: 20),
itemCount: snapshot.data.pointOfServices.length,
itemBuilder: (context, index) {
Order order = snapshot.data!.pointOfServices[index];
return Column(
children:[
Text(order['name']),// You can access this way
);
);
}),
} else {
return Text("No data");
}
},
)
I'm using Flutter with the package flutter_pagewise to add lazyloading to a large image grid which loads images from local assets.
I created json file which includes all paths for the images. With this file I want to work as future source in flutter_pagewise.
The function which returns the list from json for pagewise
Future<List> getDemoImagesJson(int offset, int limit) async {
String demoImages = await DefaultAssetBundle.of(context)
.loadString("assets/demo/demo.json");
final jsonResult = json.decode(demoImages);
List images = [];
for (var i in jsonResult) {
images.add({"id": 1, "title": "sample", "thumbnailUrl": i});
}
final list = List.from(images).toList();
var listWithOffset = list.skip(offset).toList();
final finalList = listWithOffset.getRange(0, limit).toList();
return ImageModel.fromJsonList(finalList);
}
The ImageModel class (copied from official documentation)
class ImageModel {
String title;
String id;
String thumbnailUrl;
ImageModel.fromJson(obj) {
this.title = obj['title'];
this.id = obj['id'].toString();
this.thumbnailUrl = obj['thumbnailUrl'];
}
static List<ImageModel> fromJsonList(jsonList) {
return jsonList.map<ImageModel>((obj) => ImageModel.fromJson(obj)).toList();
}
}
The PageWise Widget
PagewiseGridView.count(
shrinkWrap: true,
physics: ClampingScrollPhysics(),
pageSize: 10,
crossAxisCount: 3,
mainAxisSpacing: 8.0,
crossAxisSpacing: 8.0,
padding: EdgeInsets.all(15.0),
itemBuilder: (context, entry, index) {
return Container(
child: Image.asset(entry.thumbnailUrl,
fit: BoxFit.cover));
},
pageFuture: (pageIndex) {
return getDemoImagesJson(pageIndex * 10, 10);
})
What I expect: I expect that the Widget loads only 10 images and after I scroll down to the end of the page it loads other 10 images...until all images did load.
What I get: The Widget loads all images at once (as batch). There is no lazyload effect after reaching the bottom of the page.
Where is the issue?
Flutter newbie here. I am having a hard time trying to decode a local json list to model objects.
I am successful so far with showing what I want to show with something like:
myData[index]['id']
myData[index]['name']
But I would like to use a model object that I already created like:
rule.id
rule.name
And eventually passing the rule object through the onTap event.
This is the code I used to load json: future:DefaultAssetBundle.of(context).loadString('assets/rule.json'),
This is the code inside a FutureBuilder.
var myData = json.decode(snapshot.data);
return ListView.builder(
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(10.0),
child: ListTile(
leading: Icon(Icons.people),
title: Text(myData[index]['id']),
subtitle: Text(myData[index]['name']),
trailing: Icon(Icons.keyboard_arrow_right),
onTap: () => RuleDetailPage.show(context),
),
);
},
itemCount: myData == null ? 0 : myData.length,
);
},
)
);
The fromJson method looks like this:
factory Rule.fromJson(Map json) {
return Rule(
id: json['id'],
name: json['name'],
);
}
}
It looks like you're expecting a list of JSON objects. Just cast the result of decode to a list, and then map each JSON object into a Rule by passing it into your factory.
Like so:
var myData = json.decode(snapshot.data) as List;
List<Rule> rules = list.map((item) {
return Rule.fromJson(item);
}).toList();
return ListView.builder(
itemBuilder: (BuildContext context, int index) {i
Rule currentRule = rules[index];
return Padding(
padding: const EdgeInsets.all(10.0),
child: ListTile(
leading: Icon(Icons.people),
title: Text(currentRule.id),
subtitle: Text(currentRule.name),
trailing: Icon(Icons.keyboard_arrow_right),
onTap: () => RuleDetailPage.show(context),
),
);
},
itemCount: myData == null ? 0 : rules.length,
);
I think you are looking for a json parser: https://app.quicktype.io/
This will allow you to create a model class, and then you will be able to call your objects in the way that you suggest.
If I understood your question, you already did most of the job ;-)
json.decode(snapshot.data) return a Json object which can be a Map<String, dynamic> or a List<dynamic> regarding if the root node of your json is an object or an array.
It seems that you already implemented the fromJson factory method which is the way to go except if you want to try a parsing library as mentioned by #code-poet
So just assemble all parts of your code: var rules = Rule.fromJson(json.decode(snapshot.data)); et voilĂ !
If your snapshot.data contains an array of Rule then as mentioned json.decode returns a list and you must write: json.map((j) => Rule.fromJson(j)).toList();