在Flutter中重新加载小部件

时间:2019-10-25 10:30:46

标签: flutter dart

我有一个返回内容的API,我使用网格视图构建器将此内容放入了网格视图中,以允许分页。

我以一种无状态小部件上有一个将来的构建器的方式构造了页面,当快照完成后,我随后将快照数据传递给有状态小部件以构建网格。

一切正常,但是我现在想实现一项功能,该功能允许我在快照出错时单击重载小部件并放置重载图标来重载小部件。我怎样才能做到这一点? 以下是我未来在无状态小部件上的构建器

return new FutureBuilder<List<Things>>(
    future: apiCall(),
    builder: (context, snapshot) {
      if (snapshots.hasError)
        return //Reload Icon
      switch (snapshots.connectionState) {
        case ConnectionState.waiting:
          return Center(child: CircularProgressIndicator());
        case ConnectionState.done:
          return StatefulWidhet(things: snapshot.data);
        default:
      }
    });
} 

1 个答案:

答案 0 :(得分:0)

您需要提升状态。整个加载概念由FutureBuilder抽象,但是由于您不想一次性加载,因此这不是适合您的抽象层。这意味着,您需要自己实施“等待将来完成,然后再建造东西”,以便能够反复触发加载。

例如,您可以将所有内容都放在StatefulWidget中,并具有isLoadingdataerror属性,并正确设置它们。

由于这可能是重复执行的任务,因此您甚至可以创建一个小部件来为您处理:

import 'package:flutter/material.dart';

class Reloader<T> extends StatefulWidget {
  final Future<T> Function() loader;
  final Widget Function(BuildContext context, T data) dataBuilder;
  final Widget Function(BuildContext context, dynamic error) errorBuilder;

  const Reloader({
    Key key,
    this.loader,
    this.dataBuilder,
    this.errorBuilder,
  }) : super(key: key);

  @override
  State<StatefulWidget> createState() => ReloaderState<T>();

  static of(BuildContext context) =>
      context.ancestorStateOfType(TypeMatcher<ReloaderState>());
}

class ReloaderState<T> extends State<Reloader<T>> {
  bool isLoading = false;
  T data;
  dynamic error;

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

  Future<void> reload() async {
    setState(() {
      isLoading = true;
      data = null;
      error = null;
    });
    try {
      data = await widget.loader();
    } catch (error) {
      this.error = error;
    } finally {
      setState(() => isLoading = false);
    }
  }

  @override
  Widget build(BuildContext context) {
    if (isLoading) {
      return Center(child: CircularProgressIndicator());
    }
    return (data != null)
        ? widget.dataBuilder(context, data)
        : widget.errorBuilder(context, error);
  }
}

然后,您可以做

Reloader(
  loader: apiCall,
  dataBuilder: (context, data) {
    return DataWidget(things: data);
  },
  errorBuilder: (context, error) {
    return ...
      RaisedButton(
        onPressed: () => Reloader.of(context).reload(),
        child: Text(reload),
      ),
    ...;
  },
)

此外,我针对这种情况编写了一个程序包,该程序包具有一些内置的功能,并使用基于控制器的体系结构,而不是通过Reload.of(context)flutter_cached

搜索状态

有了它,您可以执行以下操作:

在一种状态下,创建一个CacheController(尽管您不需要缓存内容):

var controller = CacheController(
  fetcher: apiCall,
  saveToCache: () {},
  loadFromCache: () {
    throw 'There is no cache!';
  },
),

然后,您可以使用该controllerCachedBuilder方法中构建一个build

CachedBuilder(
  controller: controller,
  errorScreenBuilder: (context, error) => ...,
  builder: (context, items) => ...,
  ...
),

按下重新加载按钮后,您可以简单地调用controller.fetch()。而且,您还会在顶部获得一些很酷的功能,例如“拉动刷新”。