Flutter 有状态的代码问题。在 setstate 中放啥?

Posted

技术标签:

【中文标题】Flutter 有状态的代码问题。在 setstate 中放啥?【英文标题】:Flutter Stateful code problem. What to put in setstate?Flutter 有状态的代码问题。在 setstate 中放什么? 【发布时间】:2019-06-28 19:59:51 【问题描述】:

我从不久前开始学习颤振。我非常了解编码,但我仍然有一些问题要理解有状态以及将什么放入创建状态。按照教程,我制作了这个应用程序,它加载一个带有地震信息的 json,并显示在一个侧面有滚动条的 ListView 中。现在我想让它成为一个有状态的小部件和 onrefresh 来更新来自 json 的值。这是我的代码(无状态) `

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

Map _quakes;
List _features; // oggesto list delle features
void main() async 
  _quakes = await getQuakes();
  _features = _quakes["features"];
  runApp(new MaterialApp(
    theme: new ThemeData(
      accentColor: Colors.red,
    ),
    debugShowCheckedModeBanner: false,
    color: Colors.red,
    title: "Terremoti",
    home: new Quakes(),
  ));


class Quakes extends StatelessWidget 
  @override
  Widget build(BuildContext context) 
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Tutti i Terremoti ultime 24h"),
        centerTitle: true,
        backgroundColor: Colors.red,
      ),
      body: new Center(
          child: new Scrollbar(
        child: RefreshIndicator(
          onRefresh: getQuakes,
          child: ListView.builder(
              itemCount: _features.length,
              padding: const EdgeInsets.all(15.0),
              itemBuilder: (BuildContext context, position) 
                if (position.isOdd)
                  return new SizedBox(
                    height: 10.0,
                    child: new Center(
                      child: new Container(
                        margin: new EdgeInsetsDirectional.only(
                            start: 1.0, end: 1.0),
                        height: 2.5,
                        color: Colors.red,
                      ),
                    ),
                  );
                final index = position ~/ 2;
                var format = new DateFormat("dd MMM, yyyy, \n" + "HH:mm:ss");
                //var dateString = format.format(format);
                var date = format.format(
                    new DateTime.fromMillisecondsSinceEpoch(
                        _features[index]["properties"]["time"],
                        isUtc: true));
                //creando le righe della listview
                return new ListTile(
                  title: new Text(
                    "Magnitudo: $_features[index]["properties"]["mag"] \n $date",
                    style: new TextStyle(
                        fontSize: 21.0,
                        color: Colors.green,
                        fontWeight: FontWeight.w700),
                  ),
                  subtitle: new Text(
                    "Luogo: $_features[index]["properties"]["place"]",
                    style: new TextStyle(
                      fontSize: 18.0,
                    ),
                  ),
                );
              ),
        ),
      )),
    );
  


Future<Map> getQuakes() async 
  String apiUrl =
      "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_day.geojson";
  http.Response response = await http.get(apiUrl);
  return json.decode(response.body);

`

【问题讨论】:

【参考方案1】:

提取代码以重新加载列表,并使其成为State 类的实例方法。接下来,允许列表为空(显示进度指示器)。最后从initState调用reload方法。

import 'dart:async';
import 'dart:convert';

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

void main() async 
  runApp(MaterialApp(
    theme: ThemeData(
      accentColor: Colors.red,
    ),
    debugShowCheckedModeBanner: false,
    color: Colors.red,
    title: 'Terremoti',
    home: Quakes(),
  ));


class Quakes extends StatefulWidget 
  @override
  State createState() => QuakesState();


class QuakesState extends State<Quakes> 
  DateFormat format = DateFormat('dd MMM, yyyy, \nHH:mm:ss');
  List _features;

  @override
  void initState() 
    super.initState();
    reload();
  

  Future<void> reload() async 
    final Map quakes = await getQuakes();
    setState(() 
      _features = quakes['features'];
    );
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        title: const Text('Tutti i Terremoti ultime 24h'),
        centerTitle: true,
        backgroundColor: Colors.red,
      ),
      body: Center(
        child: _features == null
            ? const CircularProgressIndicator()
            : Scrollbar(
                child: RefreshIndicator(
                  onRefresh: reload,
                  child: ListView.builder(
                      itemCount: _features.length,
                      padding: const EdgeInsets.all(15.0),
                      itemBuilder: (BuildContext context, position) 
                        if (position.isOdd)
                          return SizedBox(
                            height: 10.0,
                            child: Center(
                              child: Container(
                                margin: const EdgeInsetsDirectional.only(
                                  start: 1.0,
                                  end: 1.0,
                                ),
                                height: 2.5,
                                color: Colors.red,
                              ),
                            ),
                          );
                        final int index = position ~/ 2;

                        final String date = format.format(
                            DateTime.fromMillisecondsSinceEpoch(
                                _features[index]['properties']['time'],
                                isUtc: true));
                        //creando le righe della listview
                        return ListTile(
                          title: Text(
                            "Magnitudo: $_features[index]["properties"]["mag"] \n $date",
                            style: const TextStyle(
                                fontSize: 21.0,
                                color: Colors.green,
                                fontWeight: FontWeight.w700),
                          ),
                          subtitle: Text(
                            "Luogo: $_features[index]["properties"]["place"]",
                            style: const TextStyle(
                              fontSize: 18.0,
                            ),
                          ),
                        );
                      ),
                ),
              ),
      ),
    );
  


Future<Map> getQuakes() async 
  final http.Response response = await http.get(
      'https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_day.geojson');
  return json.decode(response.body);

【讨论】:

非常感谢。我将检查代码以理解它。但是如何更改滚动条的颜色甚至其他一些属性?比如宽度或者在它消失之前应该保留多少时间? 通常,使用材料设计小部件,这些类型的设置由材料设计规范设置,颤振小部件遵循它们。如果您查看ScrollBar 的源代码,您会发现它们是文件const double _kScrollbarThickness = 6.0; const Duration _kScrollbarFadeDuration = Duration(milliseconds: 300); const Duration _kScrollbarTimeToFade = Duration(milliseconds: 600); 顶部的常量。顺便说一句,似乎很少使用带有ListView 的滚动条,它会自行滚动,但没有关于其运动范围的反馈。 非常感谢。您的帮助真的很有帮助。 如果有帮助,别忘了“接受”答案。 一些问题... InitState 每次应用打开时都会调用?甚至从只是背景不完全开始? Future重载不能是Future?因为它只更新数据但不返回任何内容。你能给我一个学习路径,以便更好地学习颤振吗?太多的视频太多的教程,有时我会有点困惑。你是怎么学的?再次感谢

以上是关于Flutter 有状态的代码问题。在 setstate 中放啥?的主要内容,如果未能解决你的问题,请参考以下文章

从另一个有状态小部件调用一个有状态小部件中的方法 - Flutter

Flutter:小部件状态:这段代码安全吗?

ReactJs:在使用动态 Taglist 时使用道具设置初始状态

Flutter:从子 StreamBuilder 更新有状态小部件

Flutter - 在选项卡之间移动导致丢失状态

如何通过 React Router 传递状态?