如何通过使用 json API 在列表视图中创建网格视图 [英] How to create a gridview within a listview by flutter with json API
问题描述
我想创建一个购物车应用
我遇到了问题
如何使用 JSON API 通过 flutter 在 ListView 中创建 GridView
我想要它就像这个例子:
import 'dart:convert';导入 'package:flutter/material.dart';字符串产品Json ='{"last": [{"product_id":"62","thumb":"sandwich.png","name":"Test Tilte","price":"\$55.00"}, ''{"product_id":"61","thumb":"sandwich.png","name":"Test Tilte","price":"\$55.00"}, ''{"product_id":"57","thumb":"sandwich.png","name":"Test Tilte","price":"\$55.00"}, ''{"product_id":"63","thumb":"sandwich.png","name":"Test Tilte","price":"\$55.00"}, ''{"product_id":"64","thumb":"sandwich.png","name":"Test Tilte","price":"\$55.00"}, ''{"product_id":"58","thumb":"sandwich.png","name":"Test Tilte","price":"\$55.00"}, ''{"product_id":"59","thumb":"sandwich.png","name":"Test Tilte","price":"\$55.00"}]}';字符串类别Json = '{"categories":[''{"name":"类别 1","image":"icon.png","id":2}, ''{"name":"Category 2","image":"icon.png","id":4}, ''{"name":"Category 3","image":"icon.png","id":4}, ''{"name":"Category 4","image":"icon.png","id":4}, ''{"name":"Category 5","image":"icon.png","id":6}]}';void main() =>运行应用程序(我的应用程序());class MyApp 扩展 StatelessWidget {@覆盖小部件构建(BuildContext 上下文){返回 MaterialApp(home: MyHomePage(title: 'Sliver Demo'),);}}class MyHomePage 扩展 StatefulWidget {MyHomePage({Key key, this.title}) : super(key: key);最终字符串标题;@覆盖_MyHomePageState createState() =>_MyHomePageState();}class _MyHomePageState 扩展 State{最终 ScrollController _scrollController = ScrollController();列表<动态>产品;列表<动态>类别;@覆盖初始化状态(){super.initState();映射<字符串,动态>解码 = json.decode(productsJson);产品 = 解码 ['last'];映射<字符串,动态>解码类别 = json.decode(categoriesJson);category = decodedCategories['categories'];}@覆盖小部件构建(BuildContext 上下文){返回脚手架(应用栏:应用栏(标题:文本(小部件.标题),),正文:自定义滚动视图(控制器:_scrollController,条子:<小部件>[SliverToBoxAdapter(孩子:SizedBox(高度:120.0,孩子:ListView.builder(滚动方向:Axis.horizontal,itemBuilder:(上下文,索引){映射<字符串,字符串>类别 =category[index].cast();退货卡(孩子:容器(高度:double.infinity,颜色:Colors.grey[200],孩子:中心(孩子:填充(填充:EdgeInsets.all(30.0),孩子:文本(类别[名称"]),),),),);},itemCount: 类别.长度,),),),SliverGrid(gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount: 2,childAspectRatio: 0.8,),委托:SliverChildBuilderDelegate((BuildContext 上下文,int 索引){映射<字符串,字符串>产品 =products[index].cast();退货卡(孩子:容器(颜色:Colors.grey[400],孩子:填充(填充:EdgeInsets.symmetric(垂直:30.0),孩子:中心(child: Text("Product ${product["product_id"]}")),),),);},childCount:products.length,),),],),);}}
如果您想从网络中检索 json,您可以添加/替换以下代码.添加一个返回 Future
的方法,然后使用 FutureBuilder
构建 ListView
.
<代码>....将 'package:http/http.dart' 导入为 http;导入飞镖:异步";....未来<列表<动态>>getCategories() 异步 {http.Response response = await http.get("http://159.89.228.206");映射<字符串,动态>解码类别 = json.decode(response.body);返回decodedCategories['categories'];}......SliverToBoxAdapter(孩子:SizedBox(高度:120.0,孩子:FutureBuilder(未来:getCategories(),构建器:(BuildContext上下文,AsyncSnapshot>快照){if (snapshot.connectionState == ConnectionState.done) {返回 ListView.builder(滚动方向:Axis.horizontal,itemBuilder:(上下文,索引){映射<字符串,字符串>类别 =snapshot.data[index].cast
();退货卡(孩子:容器(高度:double.infinity,颜色:Colors.grey[200],孩子:中心(孩子:填充(填充:EdgeInsets.all(30.0),孩子:文本(类别[名称"]),),),),);},itemCount:snapshot.data.length,);} 别的 {返回中心(孩子:CircularProgressIndicator());}}),),),....
I'd like to create a shopping cart app
I had a problem
How to create a GridView within a ListView by flutter with JSON API
I want it exactly like this Example :
https://i.stack.imgur.com/2KQFG.png
https://i.stack.imgur.com/I0gY8.gif
--- Update ----
About SliverGrid
I tried to fetch the products but an error appeared (This is regarding the SliverGrid part)
I/flutter ( 5992): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter ( 5992): The following assertion was thrown building FutureBuilder<List<dynamic>>(dirty, state:
I/flutter ( 5992): _FutureBuilderState<List<dynamic>>#78747):
I/flutter ( 5992): A build function returned null.
I/flutter ( 5992): The offending widget is: FutureBuilder<List<dynamic>>
I/flutter ( 5992): Build functions must never return null. To return an empty space that causes the building widget to
I/flutter ( 5992): fill available room, return "new Container()". To return an empty space that takes as little room as
I/flutter ( 5992): possible, return "new Container(width: 0.0, height: 0.0)".
With regard to ListView (It works fine)..
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'dart:async';
Future<List<dynamic>> getCategoriesApi() async {
http.Response response1 =
await http.get("http://159.89.228.206/");
Map<String, dynamic> decodedCategories = json.decode(response1.body);
//print(response1);
return decodedCategories['categories'];
}
Future<List<dynamic>> getProductsApi() async {
http.Response response =
await http.get("http://159.89.228.206/");
Map<String, dynamic> decodedCategories2 = json.decode(response.body);
// print(response);
return decodedCategories2['last'];
}
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new MyHomePage(title: 'Sliver Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => new _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final ScrollController _scrollController = new ScrollController();
List<dynamic> products;
List<dynamic> categories;
@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(widget.title),
),
body: Column(children: <Widget>[
Expanded(
child: CustomScrollView(
controller: _scrollController,
slivers: <Widget>[
SliverToBoxAdapter(
child: SizedBox(
height: 120.0,
child: FutureBuilder(
future: getCategoriesApi(),
builder: (BuildContext context,
AsyncSnapshot<List<dynamic>> snapshot) {
if (snapshot.connectionState ==
ConnectionState.done) {
return ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
Map<String, String> category =
snapshot.data[index].cast<String, String>();
return Card(
child: Container(
height: double.infinity,
color: Colors.grey[200],
child: Center(
child: Padding(
padding: EdgeInsets.all(30.0),
child: Text(category["name"]),
),
),
),
);
},
itemCount: snapshot.data.length,
);
} else {
return Center(child: CircularProgressIndicator());
}
}),
),
),
SliverToBoxAdapter(
child: Container(
child: FutureBuilder(
future: getProductsApi(),
builder: (BuildContext context,
AsyncSnapshot<List<dynamic>> snapshot) {
if (snapshot.connectionState ==
ConnectionState.done) {
SliverGrid(
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 0.8,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
Map<String, String> product = snapshot
.data[index]
.cast<String, String>();
return Card(
child: Container(
height: double.infinity,
color: Colors.grey[200],
child: Center(
child: Padding(
padding: EdgeInsets.all(30.0),
child: Text(product["name"]),
),
),
),
);
},
childCount: snapshot.data.length,
),
);
} else {
return Center(child: CircularProgressIndicator());
}
}),
),
),
],
),
)
]));
}
}
You can't embed a GridView
directly in a ListView
unless you play with the height reserved for the GridView
. If you want to maintain the scroll for both sections as you show in your images, the best thing is to use a CustomScrollView
and Slivers
.
After the image is my proposal.
import 'dart:convert';
import 'package:flutter/material.dart';
String productsJson =
'{"last": [{"product_id":"62","thumb":"sandwich.png","name":"Test Tilte","price":"\$55.00"}, '
'{"product_id":"61","thumb":"sandwich.png","name":"Test Tilte","price":"\$55.00"}, '
'{"product_id":"57","thumb":"sandwich.png","name":"Test Tilte","price":"\$55.00"}, '
'{"product_id":"63","thumb":"sandwich.png","name":"Test Tilte","price":"\$55.00"}, '
'{"product_id":"64","thumb":"sandwich.png","name":"Test Tilte","price":"\$55.00"}, '
'{"product_id":"58","thumb":"sandwich.png","name":"Test Tilte","price":"\$55.00"}, '
'{"product_id":"59","thumb":"sandwich.png","name":"Test Tilte","price":"\$55.00"}]}';
String categoriesJson = '{"categories":['
'{"name":"Category 1","image":"icon.png","id":2}, '
'{"name":"Category 2","image":"icon.png","id":4}, '
'{"name":"Category 3","image":"icon.png","id":4}, '
'{"name":"Category 4","image":"icon.png","id":4}, '
'{"name":"Category 5","image":"icon.png","id":6}]}';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(title: 'Sliver Demo'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final ScrollController _scrollController = ScrollController();
List<dynamic> products;
List<dynamic> categories;
@override
initState() {
super.initState();
Map<String, dynamic> decoded = json.decode(productsJson);
products = decoded['last'];
Map<String, dynamic> decodedCategories = json.decode(categoriesJson);
categories = decodedCategories['categories'];
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: CustomScrollView(
controller: _scrollController,
slivers: <Widget>[
SliverToBoxAdapter(
child: SizedBox(
height: 120.0,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
Map<String, String> category =
categories[index].cast<String, String>();
return Card(
child: Container(
height: double.infinity,
color: Colors.grey[200],
child: Center(
child: Padding(
padding: EdgeInsets.all(30.0),
child: Text(category["name"]),
),
),
),
);
},
itemCount: categories.length,
),
),
),
SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 0.8,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
Map<String, String> product =
products[index].cast<String, String>();
return Card(
child: Container(
color: Colors.grey[400],
child: Padding(
padding: EdgeInsets.symmetric(vertical: 30.0),
child: Center(
child: Text("Product ${product["product_id"]}")),
),
),
);
},
childCount: products.length,
),
),
],
),
);
}
}
If you want to retrieve the json from the network you can add/replace the following code. Add a method that returns a Future
and then build the ListView
using a FutureBuilder
.
....
import 'package:http/http.dart' as http;
import 'dart:async';
....
Future<List<dynamic>> getCategories() async {
http.Response response = await http.get("http://159.89.228.206");
Map<String, dynamic> decodedCategories = json.decode(response.body);
return decodedCategories['categories'];
}
...
...
SliverToBoxAdapter(
child: SizedBox(
height: 120.0,
child: FutureBuilder(
future: getCategories(),
builder: (BuildContext context, AsyncSnapshot<List<dynamic>> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return ListView.builder(
scrollDirection: Axis.horizontal,
itemBuilder: (context, index) {
Map<String, String> category =
snapshot.data[index].cast<String, String>();
return Card(
child: Container(
height: double.infinity,
color: Colors.grey[200],
child: Center(
child: Padding(
padding: EdgeInsets.all(30.0),
child: Text(category["name"]),
),
),
),
);
},
itemCount: snapshot.data.length,
);
} else {
return Center(child: CircularProgressIndicator());
}
}),
),
),
....
这篇关于如何通过使用 json API 在列表视图中创建网格视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!