Flutter ListViewBuilder Listile Header Text

186 Views Asked by At

I have a set of tabs, within one of the tabs i have a futurebuilder that has a listviewBuilder and ListTile. How do I add a header container/Sizedbox above the listtiles. I have tried adding columns, SingleChildScrollView, CustomScrollView with slivers but keeps getting errors

Widget localAttractionsTab() {
    return FutureBuilder(
        future: localAttractions(widget.locationId),
        builder: (BuildContext context, AsyncSnapshot<Amenities> snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const Center(child: CircularProgressIndicator());
          } else if (snapshot.error != null) {
            return const Center(child: Text('an error occured!'));
          } else {
            return
             ListView.builder(
                itemCount: snapshot.data!.attraction.length,
                itemBuilder: (context, index) {
                  return ListTile(
                    title: Text(snapshot.data!.attraction[index].attractionname),
                    //subtitle: Text(el.),
                    onTap: () {
                      //Got To Amenity Details Page
                      Navigator.of(context).push(
                        MaterialPageRoute(
                          builder: (context) => AttractionDetailsScreen(
                              attractionID: snapshot.data!.attraction[index].id
                             ),
                        ),
                      );
                    },
                  );
                }
            );
          }
        });
  }


2

There are 2 best solutions below

0
On BEST ANSWER

There are two ways to fix it.

The first one which I think is not too clean is alter the itemCount by adding the first widget position. You should validate first index to render the Header you want:

Widget localAttractionsTab() {
  return FutureBuilder(
      future: localAttractions(widget.locationId),
      builder: (BuildContext context, AsyncSnapshot<Amenities> snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const Center(child: CircularProgressIndicator());
        } else if (snapshot.error != null) {
          return const Center(child: Text('an error occured!'));
        } else {
          return ListView.builder(
              itemCount: snapshot.data!.attraction.length + 1,
              itemBuilder: (context, index) {
                if (index == 0) {
                  return Container(child: Text('The header!!'));
                }
                int attractionIndex = index + 1;
                return ListTile(
                  title: Text(snapshot
                      .data!.attraction[attractionIndex].attractionname),
                  //subtitle: Text(el.),
                  onTap: () {
                    //Got To Amenity Details Page
                    Navigator.of(context).push(
                      MaterialPageRoute(
                        builder: (context) => AttractionDetailsScreen(
                            attractionID: snapshot.data!.attraction[index].id),
                      ),
                    );
                  },
                );
              });
        }
      });
}

The second one consists in adding a Columnn with it's children. Take into account that you have to define the height of the Widget that containts this Column or its going throw an error:

Widget localAttractionsTab() {
  return FutureBuilder(
    future: localAttractions(widget.locationId),
    builder: (BuildContext context, AsyncSnapshot<Amenities> snapshot) {
      if (snapshot.connectionState == ConnectionState.waiting) {
        return const Center(child: CircularProgressIndicator());
      } else if (snapshot.error != null) {
        return const Center(child: Text('an error occurred!'));
      } else {
        return Column(
          children: <Widget>[
            Container(
              height: 100, // set the height of the header container as needed
              child: Center(
                child: Text(
                  'Header Container', 
                  style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold),
                ),
              ),
            ),
            Expanded(
              child: ListView.builder(
                itemCount: snapshot.data!.attraction.length,
                itemBuilder: (context, index) {
                  return ListTile(
                    title: Text(snapshot.data!.attraction[index].attractionname),
                    onTap: () {
                      Navigator.of(context).push(
                        MaterialPageRoute(
                          builder: (context) => AttractionDetailsScreen(
                            attractionID: snapshot.data!.attraction[index].id,
                          ),
                        ),
                      );
                    },
                  );
                },
              ),
            ),
          ],
        );
      }
    },
  );
}
2
On
Widget localAttractionsTab() {
    return FutureBuilder(
        future: localAttractions(widget.locationId),
        builder: (BuildContext context, AsyncSnapshot<Amenities> snapshot) {
          if (snapshot.connectionState == ConnectionState.waiting) {
            return const Center(child: CircularProgressIndicator());
          } else if (snapshot.error != null) {
            return const Center(child: Text('an error occured!'));
          } else {
            return
             ListView.builder(
                itemCount: snapshot.data!.attraction.length + 1,
                itemBuilder: (context, index) {
                  if(index == 0){
                    return Container(); // add whatever you want here
                  }
                  else{
                    return ListTile(
                    title: Text(snapshot.data!.attraction[index].attractionname),
                    //subtitle: Text(el.),
                    onTap: () {
                      //Got To Amenity Details Page
                      Navigator.of(context).push(
                        MaterialPageRoute(
                          builder: (context) => AttractionDetailsScreen(
                              attractionID: snapshot.data!.attraction[index].id
                             ),
                        ),
                      );
                    },
                  );
                  }
                  
                }
            );
          }
        });
  }