1

I'm displaying a list of Animated Containers which originally has a certain maxLines of text. When the user clicks on the container, I want the container to expand to perfectly fit the entire text

Here's my simplified code:

AnimatedContainer(
                         height: containerHeight,
                         curve: Curves.easeOut,
                         duration: Duration(milliseconds: 400),
                         child: Column(
                                   mainAxisAlignment: MainAxisAlignment.center,
                                   crossAxisAlignment: CrossAxisAlignment.start,
                                   children: [
                                     Text(searchBooksList[index].title),
                                     Text('By ${searchBooksList[index].author}'),
                                     Expanded(
                                         child: Text(
                                           '\n${searchBooksList[index].description}',
                                           overflow: TextOverflow.ellipsis,
                                           maxLines: searchBooksList[index].expanded ? 50 : 7,
                                         )
                                     ),
                                   ],
                         ),
                       )

When the user clicks on the container:

onTap: () {
            setState(() {
            searchBooksList[index].expanded = !searchBooksList[index].expanded;

            });
          },

Currently, I'm explicitly mentioning the height of the container based on the length of the text

double len;
                 if(searchBooksList[index].description.length <= 500)
                   len=0.3;
                 else if (searchBooksList[index].description.length > 500 && searchBooksList[index].description.length<=750)
                   len = 0.6;
                 else if(searchBooksList[index].description.length > 750 && searchBooksList[index].description.length<=1000)
                   len=0.66;
                 else if(searchBooksList[index].description.length > 1000 && searchBooksList[index].description.length<=1500)
                   len=1.0;
                 else if(searchBooksList[index].description.length>=1500)
                   len=1.2;
                 double containerHeight = searchBooksList[index].expanded ? 1000 * len
                     : 1000 * 0.25;

Here's what's happening now:

enter image description here

But this leaves empty lines at the end for some text. Is there a better way to fit the text without resizing the text?

zinbrox
  • 103
  • 1
  • 7

2 Answers2

0

EDIT:

SingleChildScrollView(
        child: Container(child: Column(children: [
          ExpansionPanelList(
            animationDuration: Duration(seconds: 1),
            dividerColor: Colors.white,
            children: [
              ExpansionPanel(
                  backgroundColor: Colors.grey[800],
                  canTapOnHeader: true,
                  headerBuilder: (context, isExpanded) {
                    if (isExpanded){
                      return Row(
                        children: [
                        Image.asset('assets/1.png',height: 100,width: 100,),
                        Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Text('Title',style: TextStyle(color: Colors.white),),
                            Text('By J. K. Rowling',style: TextStyle(color: Colors.white),),
                            Text(longtext, overflow: TextOverflow.ellipsis, maxLines: _isopen[0] ? 50 : 7,style: TextStyle(color: Colors.white),),
                            SizedBox(height: 10,),
                            Text('Size:0.2Mb',style: TextStyle(color: Colors.white),),
                            Text('Genre:Fantasy Fiction',style: TextStyle(color: Colors.white),),
                          ],),
                      ],);
                    }else{
                      return Row(children: [
                        Image.asset('assets/1.png',height: 100,width: 100,),
                        Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Text('Title',style: TextStyle(color: Colors.white),),
                            Text('By J. K. Rowling',style: TextStyle(color: Colors.white),),
                            Text(longtext, overflow: TextOverflow.ellipsis, maxLines: _isopen[0] ? 50 : 7,style: TextStyle(color: Colors.white),),
                            SizedBox(height: 10,),
                            Text('Size:0.2Mb',style: TextStyle(color: Colors.white),),
                            Text('Genre:Fantasy Fiction',style: TextStyle(color: Colors.white),),
                          ],),
                      ],);
                    }
                  }, body: Text(""),isExpanded: _isopen[0]),
            ],
            expansionCallback: (panelIndex, isExpanded) => setState((){
              _isopen[panelIndex]= !isExpanded;
            }),
          ),
        ],),),

      ),

Output enter image description here


This code when expanded the text completely fits the container.

 Container(
        child: Column(
          children: [
            Row(children: [
              Image.asset('assets/1.png',height: 150,width: 150,),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    AnimatedContainer(
                      curve: Curves.easeOut,
                      height: (expanded)?(MediaQuery.of(context).size.height*0.45):200,
                      duration: Duration(milliseconds: 400),
                      child: InkWell(
                        onTap: (){
                          setState(() {
                            expanded?expanded=false:expanded=true;
                          });
                        },
                        child: Column(
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Text('searchBooksList[index].title'),
                            Text('By ${'searchBooksList[index].author'}'),
                            Text('\n${longtext}', overflow: TextOverflow.ellipsis, maxLines: expanded ? 50 : 7,
                            ),
                            SizedBox(height: 10,),
                            Text("Size:0.2Mb"),
                            Text("Genre:Adventure"),
                          ],
                        ),
                      ),
                    ),

                  ],
                ),
              ),
    ],),

          ],
        ))

Gif

enter image description here

Disclaimer: While expanding it will produce A RenderFlex overflowed error

Nishuthan S
  • 1,538
  • 3
  • 12
  • 30
  • Changing the length of the text brings back the same problem however :/ – zinbrox Apr 13 '21 at 09:55
  • @zinbrox I have edited my answer. And also take a look at this https://stackoverflow.com/questions/49572747/flutter-how-to-hide-or-show-more-text-within-certain-length – Nishuthan S Apr 13 '21 at 11:21
-1

Don't give height for container just put container in Expanded widget for example :

Expanded(
    child: container(
        child: Text(
            "Put your Text Here",
        )
    )
)
  • That's not really what I'm looking for here, I need the container to change between the compressed and expanded form and hence will need the height. Using Expanded with no height container will make it all automatically expanded – zinbrox Apr 08 '21 at 10:46
  • @zinbrox you can try creating a simple bloc pattern using stream controllers.whenever you want the height changed you can pass the height to the sink so that the stream rebuilds with the given hight – Nishuthan S Apr 08 '21 at 11:44