Home > Net >  Flutter future builder to list
Flutter future builder to list

Time:02-23

I have some troubles in understanding how future builder works in flutter. I want to pass a list of String from my future call and I want to display them in a SingleChildScrollView.

The problem is that when I access the snapshot.data I can not access the element of the list. Because in my SingleChildScrollView I have container and in each container I want to display one String from the list.

This is the Future getData method with which I retrieve the data.

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;
}

And this is my future builder in which I want to display the data in each container. In the loading I added a shimmer effect.

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(),
),

So in this way I can I access the elements of my list of Strings?

CodePudding user response:

When you declare a FutureBuilder you have also to pass it it's data type. In this case it will be:

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

If you don't declare its datatype, your snapshot will be considered as an AsyncDataSnapshot<dynamic> instead of AsyncDataSnapshot<List<String>>.

CodePudding user response:

As @piskink mentioned, using ListView.builder is more efficient.

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();
    }
  },

If you still wish to use SingleChildScrollView, you can generate items like

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

Check more about async-await and Future.

  • Related