如何使用json API在Flutter中在列表视图中创建gridview [英] How to create a gridview within a listview by flutter with json API
问题描述
我想创建一个购物车应用程序
I'd like to create a shopping cart app
我遇到了问题
如何使用JSON API通过Flutter创建ListView中的GridView
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
关于SliverGrid
我试图获取产品,但是出现了错误(这与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)".
关于ListView(工作正常).
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());
}
}),
),
),
],
),
)
]));
}
}
推荐答案
除非您使用为GridView
保留的高度,否则不能将GridView
直接嵌入到ListView
中.如果要在图像中显示时都保持两个部分的滚动,最好的方法是使用CustomScrollView
和Slivers
.
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
.
图片是我的提议之后.
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,
),
),
],
),
);
}
}
如果要从网络中检索json,可以添加/替换以下代码.添加一个返回Future
的方法,然后使用FutureBuilder
构建ListView
.
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在Flutter中在列表视图中创建gridview的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!