Flutter Future Builder 上架

Flutter future builder to list

我在理解 future builder 如何在 flutter 中工作时遇到了一些麻烦。我想从我以后的调用中传递一个字符串列表,我想在 SingleChildScrollView 中显示它们。

问题是,当我访问 snapshot.data 时,我无法访问列表的元素。因为在我的 SingleChildScrollView 中我有容器并且在每个容器中我想显示列表中的一个字符串。

这是我用来检索数据的 Future getData 方法。

Future<List<String>> getData () async {
    List<String> data = [];
    data.add("A");
    data.add("B");
    data.add("C");
    // DEBUG
    await Future.delayed(const Duration(seconds: 2), (){});
    return data;
}

这是我未来的构建器,我想在其中显示每个容器中的数据。在加载中我添加了微光效果。

FutureBuilder(
  builder: (context, snapshot) {
    List<Widget> children;
    if (snapshot.hasData) {
      children = <Widget>[
        SingleChildScrollView(
          scrollDirection: Axis.horizontal,
          child: Row(
            children: [
              Container(
                margin: EdgeInsets.only(left: 5.w),
                width: 40.w,
                height: 20.h,
                decoration: BoxDecoration(
                  color: green400,
                  borderRadius: BorderRadius.all(Radius.circular(5.w)),
                ),
              ),
              Container(
                margin: EdgeInsets.only(left: 5.w),
                width: 40.w,
                height: 20.h,
                decoration: BoxDecoration(
                  color: green400,
                  borderRadius: BorderRadius.all(Radius.circular(5.w)),
                ),
              ),
              Container(
                margin: EdgeInsets.only(left: 5.w),
                width: 40.w,
                height: 20.h,
                decoration: BoxDecoration(
                  color: green400,
                  borderRadius: BorderRadius.all(Radius.circular(5.w)),
                ),
              ),
            ],
          ),
        ),
      ];
    } else if (snapshot.hasError) {
      children = <Widget>[
        const Icon(
          Icons.error_outline,
          color: Colors.red,
          size: 60,
        ),
        Padding(
          padding: const EdgeInsets.only(top: 16),
          child: Text('Error: ${snapshot.error}'),
        )
      ];
    } else {
      children = <Widget>[
        
        SingleChildScrollView(
          scrollDirection: Axis.horizontal,
          child: Row(
            children: [
              Shimmer.fromColors(
                baseColor: Colors.grey.shade200,
                highlightColor: Colors.grey.shade300,
                child: Container(
                  margin: EdgeInsets.only(left: 5.w),
                  width: 40.w,
                  height: 20.h,
                  decoration: BoxDecoration(
                    color: green400,
                    borderRadius: BorderRadius.all(Radius.circular(5.w)),
                  ),
                ),
              ),
              Shimmer.fromColors(
                baseColor: Colors.grey.shade200,
                highlightColor: Colors.grey.shade300,
                child: Container(
                  margin: EdgeInsets.only(left: 5.w),
                  width: 40.w,
                  height: 20.h,
                  decoration: BoxDecoration(
                    color: green400,
                    borderRadius: BorderRadius.all(Radius.circular(5.w)),
                  ),
                ),
              ),
              Shimmer.fromColors(
                baseColor: Colors.grey.shade200,
                highlightColor: Colors.grey.shade300,
                child: Container(
                  margin: EdgeInsets.only(left: 5.w),
                  width: 40.w,
                  height: 20.h,
                  decoration: BoxDecoration(
                    color: green400,
                    borderRadius: BorderRadius.all(Radius.circular(5.w)),
                  ),
                ),
              ),
            ],
          ),
        ),
      ];
    }
    return Center(
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: children,
      ),
    );
  },
  future: getData(),
),

那么我可以通过这种方式访问​​我的字符串列表中的元素吗?

当您声明一个 FutureBuilder 时,您还必须传递它的数据类型。在这种情况下它将是:

FutureBuilder<List<String>>(
  future: getData(),
  builder: (context,snapshot){
    return ...;
  }
)

如果您不声明其数据类型,您的 snapshot 将被视为 AsyncDataSnapshot<dynamic> 而不是 AsyncDataSnapshot<List<String>>

如@piskink 所述,使用 ListView.builder 效率更高。

body: FutureBuilder<List<String>?>(
  future: getData(),
  builder: (context, snapshot) {
    if (snapshot.hasData &&
        snapshot.connectionState == ConnectionState.done) {
      return ListView.builder(
        itemCount: snapshot.data!.length,
        itemBuilder: (context, index) {
          return Text(snapshot.data?[index] ?? "got null");
        },
      );
    }

    /// handles others as you did on question
    else {
      return CircularProgressIndicator();
    }
  },

如果您仍想使用 SingleChildScrollView,您可以生成类似

的项目
return Column(
  children: List.generate(
    snapshot.data!.length,
    (index) => Text(snapshot.data?[index] ?? "got null"),
  ),
);

查看有关 async-await and Future 的更多信息。

这是具有 Null Safty 的 FutureBuilder 的完整示例

如果您遇到这些错误:

  • (getter 'length' 没有为类型 'Object' 定义。)

  • (未为类型 'Object' 定义运算符“[]”。)

这是修复↓↓↓↓↓

修复和重要说明:

您必须 select 将接收的未来数据的数据类型。

  • 右:FutureBuilder()
  • 错误:FutureBuilder()

完整的简单示例:

import 'package:flutter/material.dart';

class FutureExample extends StatelessWidget {
  const FutureExample({Key? key}) : super(key: key);

  Future<List<String>> getData() async{
    await Future.delayed(
      const Duration(seconds:2)
    );
    return ["I'm Ramy","I'm Yasser", "I'm Ahmed", "I'm Yossif",];
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: FutureBuilder<List<String>>(
          future: getData(),
          builder: (context, snapshot) {
            return snapshot.connectionState == ConnectionState.waiting
                ? const CircularProgressIndicator()
                : Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  mainAxisSize: MainAxisSize.min,
              children: List.generate(snapshot.data!.length,
                      (index) {
                return Text(snapshot.data?[index] ?? "null") ;
                      },
              ),
            );
          },
        ),
        ),
    );
  }
}