如何通过使用 json API 在列表视图中创建网格视图 [英] How to create a gridview within a listview by flutter with json API

查看:23
本文介绍了如何通过使用 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.horizo​​ntal,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.horizo​​ntal,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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆