【问题标题】:Flutter: Build ListView After http.get RequestFlutter:在 http.get 请求之后构建 ListView
【发布时间】:2019-07-24 15:48:22
【问题描述】:

我觉得这个问题不应该花 6 个多小时来解决,但我在这里经过大量搜索和玩弄代码。 基本上,当我导航到页面时,future 会自动从 _getData() 发送 http.get 请求。我正在获取数据并构建一个 ListView 就好了,问题是我希望 ListView 仅在从 TextField 提交搜索词之后构建。任何帮助将不胜感激!

import 'dart:async';
import 'package:http/http.dart' as http;
import 'dart:convert';
import 'package:flutter/material.dart';

class FutureBuilderTestPage extends StatefulWidget {
  @override
  BuilderTestPageState createState() => BuilderTestPageState();
}

class BuilderTestPageState extends State {
  static String _searchTerm = "";
  String _url = "https://api.nal.usda.gov/ndb/search/?format=json&q=$_searchTerm&sort=n&max=20&offset=0&api_key=OMITTEDforThisPost";
  @override
  Widget build(BuildContext context) {
    var _futureBuilder = new FutureBuilder(
        future: _getData(),
        builder: (BuildContext context, AsyncSnapshot snapshot) {
            switch (snapshot.connectionState) {
              case ConnectionState.none:
                return Text('Press button to start.');
              case ConnectionState.active:
              case ConnectionState.waiting:
                return Text('Awaiting result...');
              case ConnectionState.done:
                if (snapshot.hasError) return Text('Error: ${snapshot.error}');
                // return Text('Result: ${snapshot.data}');
                return createMyListView(context, snapshot);
            }
            return null; // unreachable
        });
    return new Scaffold(
        appBar: new AppBar(
          title: Text("Appbar"),
        ),
        body: Column(
          children: <Widget>[
            Text("Search for food..."),
            TextField(
              decoration: InputDecoration(hintText: 'Search here'),
              onSubmitted: (String valueIn) {
                _searchTerm = valueIn;
              },
            ),
            Text("Results for... " + _searchTerm),
            Divider(height: 4.0),
            Expanded(child: _futureBuilder),
          ],
        ));
  }

  Future<List<dynamic>> _getData() async {
    http.Response response = await http.get(_url,
        headers: {"Accept": "Application/json"});

    final data = jsonDecode(response.body) as Map;
    final mapOfList = data['list'] as Map;
    final listOfItem = mapOfList['item'] as List<dynamic>;

    print(listOfItem.toString());

    var values = new List<dynamic>();
    for (var e in listOfItem) {
      values.add(e);
    }
    return values;
  }

  Widget createMyListView(BuildContext context, AsyncSnapshot snapshot) {
    List<dynamic> values = snapshot.data;
    return new ListView.builder(
      itemCount: values.length,
      itemBuilder: (BuildContext context, int index) {
        return new Column(
          children: <Widget>[
            new ListTile(
              title: new Text(values[index]['name']),
            )
          ],
        );
      },
    );
  }
}

class FoodObjectFromJson {
  final int offset;
  final String group;
  final String name;
  final int ndbno;
  final String ds;
  final String manu;

  FoodObjectFromJson(
      this.offset, this.group, this.name, this.ndbno, this.ds, this.manu);
}

【问题讨论】:

    标签: listview flutter future


    【解决方案1】:

    为了回答您的问题,我简化/修改了一些代码,因此不需要网络调用。

    注意布尔变量“show_results”的声明。这是你想做的事情的关键。确保记下变量的所有用法。

    在两个 setState () 构造中,它首先关闭所需列表的可见性/存在性,然后在执行搜索后打开所需列表的可见性/存在性。

    此代码已经过测试,如图所示。

    希望这会有所帮助。

    import 'dart:async';
    import 'package:http/http.dart' as http;
    import 'dart:convert';
    import 'package:flutter/material.dart';
    
    class zFutureBuilderTestPage extends StatefulWidget {
      @override
      zBuilderTestPageState createState() => zBuilderTestPageState();
    }
    
    class zBuilderTestPageState extends State {
      static String _searchTerm = "";
    
      bool show_results=false;
    
      String _url = "https://www.awebsite.com/search.php";
      @override
      Widget build(BuildContext context) {
        var _futureBuilder = new FutureBuilder(
            future: _getData(),
            builder: (BuildContext context, AsyncSnapshot snapshot) {
              switch (snapshot.connectionState) {
                case ConnectionState.none:
                  return Text('Press button to start.');
                case ConnectionState.active:
                case ConnectionState.waiting:
                  return Text('Awaiting result...');
                case ConnectionState.done:
                  if (snapshot.hasError) return Text('Error: ${snapshot.error}');
                  // return Text('Result: ${snapshot.data}');
                  return createMyListView(context, snapshot);
              }
              return null; // unreachable
            });
        return new Scaffold(
            appBar: new AppBar(
              title: Text("Appbar"),
            ),
            body: Column(
              children: <Widget>[
                Text("Search for food..."),
                TextField(
                  decoration: InputDecoration(hintText: 'Search here'),
                  onSubmitted: (String valueIn) => search(valueIn),
                ),
                Text("Results for... " + _searchTerm),
                Divider(height: 4.0),
                show_results == false ? new Container ( width: 0, height: 0 ) : Expanded(child: _futureBuilder),
              ],
            ));
      }
    
      Future <List<dynamic>> search ( String valueIn ) async {
        print (valueIn);
        setState(() {
          show_results=false;
        });
    
        List<dynamic> l = await _getData();
    
        setState(() {
          show_results=true;
        });
        return ( l );
      }
    
      Future<List<dynamic>> _getData() async {
    
        List<FoodObjectFromJson> values=new List();
        FoodObjectFromJson H =new FoodObjectFromJson(5,"Orange");
        values.add( H );
        FoodObjectFromJson H2 =new FoodObjectFromJson(8,"Apple");
        values.add( H2 );
        FoodObjectFromJson H3 =new FoodObjectFromJson(22,"Pear");
        values.add( H3 );
    
    
        return values;
      }
    
      Widget createMyListView(BuildContext context, AsyncSnapshot snapshot) {
        List<dynamic> values = snapshot.data;
        return new ListView.builder(
          itemCount: values.length,
          itemBuilder: (BuildContext context, int index) {
            return new Column(
              children: <Widget>[
                new ListTile(
                  title: new Text(values[index].fruit_handle),
                )
              ],
            );
          },
        );
      }
    }
    
    class FoodObjectFromJson {
      final int fruit_id;
      final String fruit_handle;
    
      FoodObjectFromJson(
          this.fruit_id, this.fruit_handle);
    }
    

    【讨论】:

    • 顺便说一句,它应该与您的http调用基本相同,只是我无法访问您的网站搜索。
    • 谢谢布拉德福德先生!我喜欢你在那里所做的,这绝对有帮助。现在,行为符合预期,但我对学习状态行为以及如何操作它是新手。也就是说,当页面被路由到时,HTTP 调用仍然会立即调用,而不是等待搜索词被提交。然后它在提交时也会调用 x4 ,并且变量在 _url 内没有变化,即无论输入什么字符串,总是返回默认搜索。将在此工作并在/如果我找到解决方案时发布。 ~再次感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-25
    • 2016-10-22
    • 2019-01-01
    • 2013-06-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多