繁体   English   中英

如何使用 RefreshIndicator 更新 FutureBuilder state?

[英]How to use RefreshIndicator to update FutureBuilder state?

我正在使用FutureBuilder来显示从服务器加载的数据。 我只想在应用程序启动时显示加载 state 一次,这就是我从 initState 调用 API 的原因。 我从服务器获得的数据可能会发生变化,为了反映 UI 的变化,我正在使用refreshIndicator 问题是我无法想出更新 state 的解决方案。

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
      GlobalKey<RefreshIndicatorState>();
  Future<List<Photo>> _photosServer;

  @override
  void initState() {
    super.initState();
    _photosServer = ApiRest.getPhotos();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: RefreshIndicator(
        key: _refreshIndicatorKey,
        onRefresh: () {
          _refreshIndicatorKey.currentState.show();
          await getPhotosFromServer();
          ...
        },
        child: FutureBuilder(
          future: _photosServer,
          builder: (BuildContext context, snapshot) {
            if (snapshot.data == null) {
              return Center(
                child: Text('Loading...'),
              );
            }
            return ListView.builder(
              itemCount: snapshot.data.length,
              itemBuilder: (BuildContext context, index) => ListTile(
                title: Text(snapshot.data[index].title),
              ),
            );
          },
        ),
      ),
    );
  }
}

onRefresh function 中,我使用以下代码在从服务器获取数据时显示 RefreshIndicator。

onRefresh: () {
          _refreshIndicatorKey.currentState.show();
          await getPhotosFromServer();

           ...

        }

我还应该做些什么来处理这个问题?

你可以有一个单独的List<Photo>变量,它可以由 FutureBuilder 或 RefreshIndicator 更新,并执行以下操作:

class _MyHomePageState extends State<MyHomePage> {
  GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
      GlobalKey<RefreshIndicatorState>();
  List<Photo> _photosList;
  Future<void> _initPhotosData;

  @override
  void initState() {
    super.initState();
    _initPhotosData = _initPhotos();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: FutureBuilder(
        future: _initPhotosData,
        builder: (BuildContext context, snapshot) {
          switch (snapshot.connectionState) {
            case ConnectionState.none:
            case ConnectionState.waiting:
            case ConnectionState.active:
              {
                return Center(
                  child: Text('Loading...'),
                );
              }
            case ConnectionState.done:
              {
                return RefreshIndicator(
                    key: _refreshIndicatorKey,
                    onRefresh: _refreshPhotos,
                    child: ListView.builder(
                      itemCount: _photosList.length,
                      itemBuilder: (BuildContext context, index) => ListTile(
                        title: Text(_photosList[index].title),
                      ),
                    ));
              }
          }
        },
      ),
    );
  }

  Future<void> _initPhotos() async {
    final photos = await ApiRest.getPhotos();
    _photosList = photos;
  }

  Future<void> _refreshPhotos() async {
    final photos = await ApiRest.getPhotos();
    setState(() {
      _photosList = photos;
    });
  }
}
onRefresh: () {
   return Future(() { setState(() {}); });
},

在您的 RefreshIndicator 将刷新子 FutureBuilder

为了刷新数据并显示刷新指示器,只需等待结果然后更新未来:

onRefresh: () async {
  final results = await getPhotosFromServer();
  setState(() {
    _photosServer = Future.value( results );
  });
},

我创建了一个小部件来处理这种情况

您可以像 FutureBuilder 一样简单地使用它,除了您必须提供 function 调用而不是 Future

import 'package:flutter/material.dart';

class RefreshIndicatorFutureBuilder<T> extends StatefulWidget {
  const RefreshIndicatorFutureBuilder({
    super.key,
    required this.future,
    required this.builder,
  });

  final Future<T> Function() future;

  final Widget Function(BuildContext, AsyncSnapshot<T> snapshot) builder;

  @override
  State<RefreshIndicatorFutureBuilder<T>> createState() =>
      _RefreshIndicatorFutureBuilderState<T>();
}

class _RefreshIndicatorFutureBuilderState<T>
    extends State<RefreshIndicatorFutureBuilder<T>> {
  late Future<T> Function() future = widget.future;

  @override
  Widget build(BuildContext context) {
    return RefreshIndicator(
      onRefresh: () async {
        setState(() {
          future = widget.future;
        });
      },
      child: FutureBuilder<T>(future: future(), builder: widget.builder),
    );
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM