Ayaz Khalid
Ayaz Khalid

Reputation: 141

Dynamic height of listview builder item

I am unable to set the dynamic size to my list item of list view builder, every time it shows blank screen and when I specify a constant size it works.

I tried by using column by setting mainAxisSize=minimum and by using container as we know container wraps the child height but nothing works

 listItem (GuideLines news) =>Column(
    mainAxisAlignment: MainAxisAlignment.start,
    mainAxisSize:  MainAxisSize.min,
    children: <Widget>[Container(
      decoration: BoxDecoration(image: new DecorationImage(image: AdvancedNetworkImage(
        "${news.featured_image}",
        useDiskCache: true,
        cacheRule: CacheRule(maxAge: const Duration(days: 7)),
      ),fit: BoxFit.cover)),
      margin: EdgeInsets.only(bottom: 10.0),
      child: ListTile(
        onTap: (){
          print(news.web_link);
          Navigator.push(context, MaterialPageRoute(builder: (context) => NewsDetailsPage(news)));
        },
        title: new Container(
            margin: EdgeInsets.only(left: 30.0),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.start,
              crossAxisAlignment: CrossAxisAlignment.start,
              mainAxisSize: MainAxisSize.max,
              children: <Widget>[
                Padding(
                  padding: const EdgeInsets.only(top: 20.0),
                  child: new Text("${DateFormat("E, d MMM y").format(CommonService.dateFormat(news.publish_date.toString()))}", style: TextStyle(fontFamily: 'SF-Display-Regular' ,fontSize: 13.0 ,color: Colors.white),),
                ),
                SizedBox(height: 13.0),
                new Flexible(
                  child: new Container( width:  MediaQuery.of(context).size.width  *0.45,
                      child: Padding(
                        padding: const EdgeInsets.only(bottom: 20.0),
                        child: new Text("${news.title}" ,maxLines: 3, overflow: TextOverflow.ellipsis, style: TextStyle(fontFamily: 'SF-Display-Semibold' ,fontSize: 22.0 ,color: Colors.white),),
                      )


                  ),
                )
              ],
            )),
        trailing: Padding(
          padding: const EdgeInsets.only(right: 20),
          child: Row(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[Icon(Icons.arrow_forward_ios, color: Colors.white),SizedBox(width: 8,)],
          ),
        ),
      ),


    )],
  );

Upvotes: 7

Views: 24674

Answers (2)

Muhammad Tameem Rafay
Muhammad Tameem Rafay

Reputation: 4575

Just add these two properties of shrinkWrap and physics to make the height of list dynamic

ListView.builder(
   shrinkWrap: true,
   physics: NeverScrollableScrollPhysics(), //Optional                               
   itemCount: size,
   itemBuilder: (context, position) {}
),

Upvotes: 10

Martin Niederl
Martin Niederl

Reputation: 759

The problem with your code is, that you used a Flexible widget in a Column. A Flexible widget expands to the remaining space of the Column or Row. However, this only works if you have restricted the size of the Column or Row widget. Because otherwise, the size of the element in the Column would expand to infinity as the remaining space is not restricted and therefore also infinity.

When using Flexible or Expanded widgets you always need to restrict their parent size, else you get this error:

RenderFlex children have non-zero flex but incoming height constraints are unbounded. When a column is in a parent that does not provide a finite height constraint, for example if it is in a vertical scrollable, it will try to shrink-wrap its children along the vertical axis. Setting a flex on a child (e.g. using Expanded) indicates that the child is to expand to fill the remaining space in the vertical direction.

The solution and some cleanup of your code:

Widget listItem(GuideLines news) {
  return Container(
    decoration: BoxDecoration(
      image: DecorationImage(
          image: AdvancedNetworkImage(
            "${news.featured_image}",
            useDiskCache: true,
            cacheRule: CacheRule(maxAge: const Duration(days: 7)),
          ),
          fit: BoxFit.cover),
    ),
    margin: EdgeInsets.only(bottom: 10.0),
    child: ListTile(
      onTap: () {
        print(news.web_link);
        Navigator.push(context, MaterialPageRoute(builder: (context) => NewsDetailsPage(news)));
      },
      title: Container(
        margin: EdgeInsets.only(left: 30.0),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.only(top: 20.0, bottom: 13.0),
              child: Text(
                "${DateFormat("E, d MMM y").format(CommonService.dateFormat(news.publish_date.toString()))}",
                style: TextStyle(fontFamily: 'SF-Display-Regular', fontSize: 13.0, color: Colors.white),
              ),
            ),
            Container(
              width: MediaQuery.of(context).size.width * 0.45,
              padding: const EdgeInsets.only(bottom: 20.0),
              child: new Text(
                "${news.title}",
                maxLines: 3,
                overflow: TextOverflow.ellipsis,
                style: TextStyle(fontFamily: 'SF-Display-Semibold', fontSize: 22.0, color: Colors.white),
              ),
            )
          ],
        ),
      ),
      trailing: Padding(
        padding: const EdgeInsets.only(right: 28),
        child: Icon(Icons.arrow_forward_ios, color: Colors.white),
      ),
    ),
  );
}

In your specific case, this Flexible widget was redundant anyway.

Upvotes: 3

Related Questions