Tushar Pol
Tushar Pol

Reputation: 7629

Flutter: How to hide or show more text within certain length

My Container having a description of movies.

Initially, I want to show only a few lines of description. And below that there should be a link (more...), After Tapping more... all content of description should be get displayed.

For example, check this JQuery plugin.

Upvotes: 57

Views: 98620

Answers (15)

Ryan Sneyd
Ryan Sneyd

Reputation: 199

AnimatedCrossFade(
   duration: Duration(milliseconds: 100),
   firstChild: Text(
      "Short text",
      key: ValueKey<int>(0),
      overflow: TextOverflow.ellipsis,
      maxLines: 2,
   ),
   secondChild: Text(
      "short text that can be longer",
      key: ValueKey<int>(1),
   ),
   crossFadeState: isVisible ? CrossFadeState.showFirst : CrossFadeState.showSecond,
),
SizedBox(
   height: 10,
),
Center(
   child: TextButton.icon(
   onPressed: () {
      setState(() {
         isVisible = !isVisible;
      });
    },
    icon: Text("View More"),
    label: Icon(Icons.keyboard_arrow_down),
)

Upvotes: 1

Marim mohamed
Marim mohamed

Reputation: 141

Easily by using a bool:

open

var with default value = false,

Then, create a button to-->

 setState(() {
   open = !open;
 });

After That,

open == true
     ? Text(
         des,//your long text. in hidden mode
         style: TextStyle(color: black),
         maxLines: 3,//by controlling the no. lines will appear
         overflow: TextOverflow.ellipsis,//shape of disappeared txt
       )
     : Text(
         des,//your long text in normal view.
         style: TextStyle(color: black),

in hidden

enter image description here

in normal

enter image description here

Upvotes: 0

0tieno_okeyo
0tieno_okeyo

Reputation: 1

Using maxLines on the text widget gives a clean and precise result. Change the reveal bool value when the user clicks on the text. Hope this helps someone.

class SingleReview extends StatefulWidget {
  const SingleReview({
    Key? key,
    required this.reviewText,
  }) : super(key: key);
  final String reviewText;
  @override
  State<SingleReview> createState() => _SingleReviewState();
}

class _SingleReviewState extends State<SingleReview> {
  bool reveal = false;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(
        horizontal: 18.0,
        vertical: 10,
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
   
          InkWell(
            onTap: () {
              setState(() {
                reveal = !reveal;
              });
            },
            child: Text(
              widget.reviewText,
              maxLines: reveal ? 2 : null,
              overflow: reveal ? TextOverflow.ellipsis : null,
            ),
          ),
        ],
      ),
    );
  }
}

Upvotes: 0

Temirlan Ayazbek
Temirlan Ayazbek

Reputation: 11

1st screenshot Show less

2nd screenshot Show more

3rd screenshot When text length less than 197

Code:

bool isExpanded = false;
Column(
                children: [
                  Align(
                    alignment: Alignment.topLeft,
                    child: Text(
                      widget.title,
                      style: TextStyles.regularStyle.copyWith(
                        color: const Color(0xFF1A1A1A),
                      ),
                      maxLines: isExpanded ? 11 : 4,
                      softWrap: true,
                      // overflow: TextOverflow.fade,
                    ),
                  ),
                  const SizedBox(
                    height: 4,
                  ),
                  widget.title.length < 197
                      ? SizedBox()
                      : InkWell(
                          onTap: () {
                            setState(() {
                              isExpanded = !isExpanded;
                            });
                          },
                          child: Align(
                            alignment: Alignment.topLeft,
                            child: Text(
                              isExpanded == false
                                  ? 'Показать полностью...'
                                  : 'Show less',
                              style: TextStyles.mediumStyle.copyWith(
                                fontSize: 14,
                                color: const Color(0xff3D3DD8),
                              ),
                              maxLines: 1,
                            ),
                          ),
                        ),
                ],
              ),

Code in pastebin

Full code resources

Upvotes: -1

Remoo
Remoo

Reputation: 747

This an old question, but hope this could help anybody who looks for simple fast solution with simple code: Just check if the text less than (for example) 125 chars, then show the whole text, if not show the first 125 chars then use '... show more' as textspan where when you click on it show the whole text and change 'show more' with 'show less'

I am using here getx for state mang, if you are not using it just use statefull screen with setstate to change its value

final RxBool showLongDes = false.obs;
final String shortDescription = 'This is great product ...'
...

shortDescription.length <= 125

? Text(shortDescription)      
:Obx(() {
   return RichText(
       text: TextSpan(
         text: showLongDes.value
               ?shortDescription
                : shortDescription.substring(0, 125) + ' ... '
          children: [
             TextSpan(
                 text: showLongDes.value
                        ? ' ' + 'Show less'
                        : 'Show more',
                 recognizer: TapGestureRecognizer()
                       ..onTap = () => showLongDes.value =!showLongDes.value,
                 style: GoogleFonts.rubik(
                          color: Colors.blue,
                            decoration: TextDecoration.underline),
             )
          ],
       ),
);
                            

Upvotes: 3

Option 1: if you are looking for something like facebook,Linkedin you just need one variable isOpen. If isOpen true return MoreText else LessText (use substring) . May not be a perfect solution but you can get what you need

Warning!!! you have to handle text length when using substring

import 'package:flutter/material.dart';
import 'package:linky/presentation/extension/utils.dart';

class ExpandableText extends StatefulWidget {
  final String text;
  final double max;
  const ExpandableText({Key? key, required this.text, required this.max})
      : super(key: key);

  @override
  _ExpandableTextState createState() => _ExpandableTextState();
}

class _ExpandableTextState extends State<ExpandableText> {
  TextPainter? textPainter;
  bool isOpen = false;

  @override
  Widget build(BuildContext context) {
    return isOpen
        ? SizedBox(
            child: Align(
                alignment: Alignment.centerLeft,
                child: RichText(
                  textAlign: TextAlign.start,
                  text: TextSpan(children: [
                    TextSpan(
                        text: widget.text, style: textTheme(context).bodyText1),
                    WidgetSpan(
                        child: InkWell(
                            onTap: () {
                              setState(() {
                                isOpen = !isOpen;
                              });
                            },
                            child: Text(
                              "Less more",
                              style: textTheme(context).bodyText1!.copyWith(
                                  fontWeight: FontWeight.bold,
                                  color: Colors.blueAccent),
                            )),
                        style: textTheme(context).bodyText1)
                  ]),
                )))
        : Align(
            alignment: Alignment.centerLeft,
            child: RichText(
              textAlign: TextAlign.start,
              maxLines: 2,
              text: TextSpan(children: [
                TextSpan(
                    text: widget.text.substring(
                            0,
                            int.parse(
                                "${(widget.text.length * widget.max).toInt()}")) +
                        "...",
                    style: textTheme(context).bodyText1),
                WidgetSpan(
                    child: InkWell(
                        mouseCursor: SystemMouseCursors.click,
                        onTap: () {
                          setState(() {
                            isOpen = !isOpen;
                          });
                        },
                        child: Text(
                          "more",
                          style: textTheme(context).bodyText1!.copyWith(
                              fontWeight: FontWeight.bold,
                              color: Colors.blueAccent),
                        )),
                    style: textTheme(context).bodyText1)
              ]),
            ),
          );
  }
}

Exemple :

ExpandableText(
          text: users[0].loremIpsum,
          max: 0.2,
        )

Option 2: If you need something like ExpansionPanel you juste use widget ExpansionTile .

ExpansionTile(title: title,children: [])

Inside Childress moreText & title your LessText . You can hide LessText when isOpen

enter image description here

Upvotes: 2

Prince soni
Prince soni

Reputation: 159

I examine all the answer and make a good solution. Just pass your text here and you can change number of lines just by changing maxLines in text widget..

class ExpandableText extends StatefulWidget {
  final String text;
  const ExpandableText(this.text, {Key? key}) : super(key: key);

  @override
  _ExpandableTextState createState() => _ExpandableTextState();
}

class _ExpandableTextState extends State<ExpandableText>
    with TickerProviderStateMixin<ExpandableText> {
  bool isExpanded = false;
  late int numLines;

 @override
 void initState() {
   numLines = '\n'.allMatches(widget.text).length + 1;
   super.initState();
 }

  @override
  Widget build(BuildContext context) {
    return SizedBox(
      width: double.infinity,
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          AnimatedSize(
            duration: const Duration(milliseconds: 200),
            child: Text(
                widget.text,
                maxLines: isExpanded ? null : 3,
                softWrap: true,
                overflow: TextOverflow.fade,
              ),
          ),
         numLines > 2
          ? TextButton(
              child: const Text('View more'),
              onPressed: () => setState(() => 
                   isExpanded = !isExpanded),
            )
          : const SizedBox()
        ],
      ),
    );
  }
}

Upvotes: -1

Taba
Taba

Reputation: 4336

If you want to just use a package to simply do it, you can use the Readmore package. its working just fine and so simple to use.

import 'package:readmore/readmore.dart';

ReadMoreText(
  'Flutter is Google’s mobile UI open source framework to build high-quality native (super fast) interfaces for iOS and Android apps with the unified codebase.',
  trimLines: 2,
  colorClickableText: Colors.pink,
  trimMode: TrimMode.Line,
  trimCollapsedText: 'Show more',
  trimExpandedText: 'Show less',
  moreStyle: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
);

Upvotes: 13

Prafulla
Prafulla

Reputation: 771

To get Exact Behavior like JQuery plugin. you need to use TextPainter and calculate the hight on given Width.

Expanded State

Normal State

import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';

void main() => runApp(MaterialApp( home: DemoApp()));

class DemoApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          title: Text(
            'Read More Text',
          )),
      body:  SingleChildScrollView(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Padding(
                padding: const EdgeInsets.all(16.0),
                child: ExpandableText(
                  'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque scelerisque efficitur posuere. Curabitur tincidunt placerat diam ac efficitur. Cras rutrum egestas nisl vitae pulvinar. Donec id mollis diam, id hendrerit neque. Donec accumsan efficitur libero, vitae feugiat odio fringilla ac. Aliquam a turpis bibendum, varius erat dictum, feugiat libero. Nam et dignissim nibh. Morbi elementum varius elit, at dignissim ex accumsan a',
                   trimLines: 2,
                ),
              ),
            ],
          ),
        ),
    );
  }
}
class ExpandableText extends StatefulWidget {
  const ExpandableText(
      this.text, {
        Key key,
        this.trimLines = 2,
      })  : assert(text != null),
        super(key: key);

  final String text;
  final int trimLines;

  @override
  ExpandableTextState createState() => ExpandableTextState();
}

class ExpandableTextState extends State<ExpandableText> {
  bool _readMore = true;
  void _onTapLink() {
    setState(() => _readMore = !_readMore);
  }

  @override
  Widget build(BuildContext context) {
    final DefaultTextStyle defaultTextStyle = DefaultTextStyle.of(context);
    final colorClickableText = Colors.blue;
    final widgetColor = Colors.black;
    TextSpan link = TextSpan(
      text: _readMore ? "... read more" : " read less",
      style: TextStyle(
        color: colorClickableText,
      ),
      recognizer: TapGestureRecognizer()..onTap = _onTapLink
    );
    Widget result = LayoutBuilder(
      builder: (BuildContext context, BoxConstraints constraints) {
        assert(constraints.hasBoundedWidth);
        final double maxWidth = constraints.maxWidth;
        // Create a TextSpan with data
        final text = TextSpan(
          text: widget.text,
        );
        // Layout and measure link
        TextPainter textPainter = TextPainter(
          text: link,
          textDirection: TextDirection.rtl,//better to pass this from master widget if ltr and rtl both supported
          maxLines: widget.trimLines,
          ellipsis: '...',
        );
        textPainter.layout(minWidth: constraints.minWidth, maxWidth: maxWidth);
        final linkSize = textPainter.size;
        // Layout and measure text
        textPainter.text = text;
        textPainter.layout(minWidth: constraints.minWidth, maxWidth: maxWidth);
        final textSize = textPainter.size;
        // Get the endIndex of data
        int endIndex;
        final pos = textPainter.getPositionForOffset(Offset(
            textSize.width - linkSize.width,
            textSize.height,
        ));
        endIndex = textPainter.getOffsetBefore(pos.offset);
        var textSpan;
        if (textPainter.didExceedMaxLines) {
          textSpan = TextSpan(
            text: _readMore
                ? widget.text.substring(0, endIndex)
                : widget.text,
            style: TextStyle(
              color: widgetColor,
            ),
            children: <TextSpan>[link],
          );
        } else {
          textSpan = TextSpan(
            text: widget.text,
          );
        }
        return RichText(
          softWrap: true,
          overflow: TextOverflow.clip,
          text: textSpan,
        );
      },
    );
    return result;
  }
}

Upvotes: 39

sarin upreti
sarin upreti

Reputation: 346

ExpandableText with regrex validation as well.

import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';

class ExpandableText extends StatefulWidget {
  ExpandableText(this.text);

  final String text;
  // bool isExpanded = false;

  @override
  _ExpandableTextState createState() => new _ExpandableTextState();
}

class _ExpandableTextState extends State<ExpandableText> {
  String text;
  bool canExpand = false;
  bool isExpand = false;

  @override
  Widget build(BuildContext context) {
    //
    canExpand = widget.text != null && widget.text.length >= 150;
    text = canExpand
        ? (isExpand ? widget.text : widget.text.substring(0, 150))
        : (widget.text);

    return canExpand
        ? Column(
            mainAxisAlignment: MainAxisAlignment.start,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              buildTextWithLinks(text.trim()),
              GestureDetector(
                onTap: () {
                  setState(() {
                    isExpand = !isExpand;
                  });
                },
                child: Padding(
                  padding: const EdgeInsets.symmetric(vertical: 4.0),
                  child: Text(isExpand ? ' ... show less' : ' ... show more'
                  ),
                ),
              ),
            ],
          )
        : Text(text != null ? text : "");
  }
}

Text buildTextWithLinks(String textToLink, {String text}) =>
    Text.rich(TextSpan(children: linkify(textToLink)));

Future<void> openUrl(String url) async {
  if (await canLaunch(url)) {
    await launch(url);
  } else {
    throw 'Could not launch $url';
  }
}

const String urlPattern =
    r"(https?|http)://([-A-Z0-9.]+)(/[-A-Z0-9+&@#/%=~_|!:,.;]*)?(\?[A-Z0-9+&@#/%=~_|!:‌​,.;]*)?";
const String emailPattern = r'\S+@\S+';
const String phonePattern = r'[\d-]{9,}';
final RegExp linkRegExp = RegExp(
    '($urlPattern)|($emailPattern)|($phonePattern)',
    caseSensitive: false);

WidgetSpan buildLinkComponent(String text, String linkToOpen) => WidgetSpan(
        child: InkWell(
      child: Text(
        text,
        style: TextStyle(
          color: Colors.red,
          decoration: TextDecoration.underline,
        ),
      ),
      onTap: () => openUrl(linkToOpen),
    ));

List<InlineSpan> linkify(String text) {
  final List<InlineSpan> list = <InlineSpan>[];
  final RegExpMatch match = linkRegExp.firstMatch(text);
  if (match == null) {
    list.add(TextSpan(text: text));
    return list;
  }

  if (match.start > 0) {
    list.add(TextSpan(text: text.substring(0, match.start)));
  }

  final String linkText = match.group(0);
  if (linkText.contains(RegExp(urlPattern, caseSensitive: false))) {
    list.add(buildLinkComponent(linkText, linkText));
  } else if (linkText.contains(RegExp(emailPattern, caseSensitive: false))) {
    list.add(buildLinkComponent(linkText, 'mailto:$linkText'));
  } else if (linkText.contains(RegExp(phonePattern, caseSensitive: false))) {
    list.add(buildLinkComponent(linkText, 'tel:$linkText'));
  } else {
    throw 'Unexpected match: $linkText';
  }

  list.addAll(linkify(text.substring(match.start + linkText.length)));

  return list;
}

Upvotes: 3

Avnish Nishad
Avnish Nishad

Reputation: 1862

Widget _text() {
var exceeded;
return LayoutBuilder(builder: (context, size) {
  // Build the textspan
  var span = TextSpan(
    text:
        "The red-tailed tropicbird is a seabird native to the tropical Indian and Pacific Oceans. One of three closely related species of tropicbird, it has four subspecies. Text wrapping is quite a pain for me too. I find that putting Text in a Container and then wrapping that container in a Expanded/Flexible works well.",
    style: Theme.of(context).textTheme.body1.copyWith(color: Colors.white),
  );

  // Use a textpainter to determine if it will exceed max lines
  var tp = TextPainter(
    maxLines: _maxLine.toInt(),
    textAlign: TextAlign.left,
    textDirection: TextDirection.ltr,
    text: span,
  );

  // trigger it to layout
  tp.layout(maxWidth: size.maxWidth);

  // whether the text overflowed or not
  exceeded = tp.didExceedMaxLines;

  // return Column(children: <Widget>[
  return Container(
    child: exceeded && seeMoreClicked
        ? _seeMoreLess(span, "See Less ")
        : exceeded && !seeMoreClicked
            ? _seeMoreLess(span, "See More", 3)
            : Text.rich(
                span,
                overflow: TextOverflow.visible,
              ),
  );
});
}

Widget _seeMoreLess(TextSpan span, String _text, [int maxLine = 0]) {
return Column(
  mainAxisAlignment: MainAxisAlignment.start,
  crossAxisAlignment: CrossAxisAlignment.end,
  children: <Widget>[
    maxLine > 0
        ? Text.rich(
            span,
            overflow: TextOverflow.ellipsis,
            maxLines: 3,
          )
        : Text.rich(
            span,
            overflow: TextOverflow.visible,
          ),
    InkWell(
        child: Text(
          _text,
          style: Theme.of(context)
              .textTheme
              .body1
              .copyWith(color: Colors.blue),
        ),
        onTap: () {
          setState(() {
            seeMoreClicked = !seeMoreClicked;
          });
        }),
  ],
);

Upvotes: 1

chunhunghan
chunhunghan

Reputation: 54397

Please use package flutter-expandable.
This package can produce an effect of expanding an image or text.
https://github.com/aryzhov/flutter-expandable

enter image description here

import 'package:expandable/expandable.dart';
...
ExpandablePanel(
        header: Text( content,
          maxLines: 2,
          style: Theme.of(context).textTheme.body2,
        ),
        expanded: Align(
            alignment: Alignment.centerLeft,
            child: Text(
              content,
              softWrap: true,
            )),
        tapHeaderToExpand: true,
        hasIcon: true,
      ),

Upvotes: 4

Vicky Salunkhe
Vicky Salunkhe

Reputation: 11005

Try this.

Watch the output from here ( Video )

or refer below images

enter image description here

import 'package:flutter/material.dart';

class DemoPage extends StatefulWidget {
  final Widget child;

  DemoPage({Key key, this.child}) : super(key: key);

  _DemoPageState createState() => _DemoPageState();
}

class _DemoPageState extends State<DemoPage> {

String descText = "Description Line 1\nDescription Line 2\nDescription Line 3\nDescription Line 4\nDescription Line 5\nDescription Line 6\nDescription Line 7\nDescription Line 8";
bool descTextShowFlag = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("DemoPage"),
      ),
      body: new Container(
        margin: EdgeInsets.all(16.0),
        child: new Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
              Text(descText,
                maxLines: descTextShowFlag ? 8 : 2,textAlign: TextAlign.start),
              InkWell(
                onTap: (){ setState(() {
                descTextShowFlag = !descTextShowFlag; 
                }); },
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.end,
                  children: <Widget>[
                    descTextShowFlag ? Text("Show Less",style: TextStyle(color: Colors.blue),) :  Text("Show More",style: TextStyle(color: Colors.blue))
                  ],
                ),
              ),
          ],
        ),
      ),
    );
  }
}

Upvotes: 10

Ajay
Ajay

Reputation: 16300

you can do that this way

example

import 'package:flutter/material.dart';
import 'package:meta/meta.dart';

void main() => runApp(new MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Flutter Demo',
      home: new HomeScreen(),
    );
  }
}

class HomeScreen extends StatelessWidget {
  final String description =
      "Flutter is Google’s mobile UI framework for crafting high-quality native interfaces on iOS and Android in record time. Flutter works with existing code, is used by developers and organizations around the world, and is free and open source.";

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: const Text("Demo App"),
      ),
      body: new Container(
        child: new DescriptionTextWidget(text: description),
      ),
    );
  }
}

class DescriptionTextWidget extends StatefulWidget {
  final String text;

  DescriptionTextWidget({@required this.text});

  @override
  _DescriptionTextWidgetState createState() => new _DescriptionTextWidgetState();
}

class _DescriptionTextWidgetState extends State<DescriptionTextWidget> {
  String firstHalf;
  String secondHalf;

  bool flag = true;

  @override
  void initState() {
    super.initState();

    if (widget.text.length > 50) {
      firstHalf = widget.text.substring(0, 50);
      secondHalf = widget.text.substring(50, widget.text.length);
    } else {
      firstHalf = widget.text;
      secondHalf = "";
    }
  }

  @override
  Widget build(BuildContext context) {
    return new Container(
      padding: new EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0),
      child: secondHalf.isEmpty
          ? new Text(firstHalf)
          : new Column(
              children: <Widget>[
                new Text(flag ? (firstHalf + "...") : (firstHalf + secondHalf)),
                new InkWell(
                  child: new Row(
                    mainAxisAlignment: MainAxisAlignment.end,
                    children: <Widget>[
                      new Text(
                        flag ? "show more" : "show less",
                        style: new TextStyle(color: Colors.blue),
                      ),
                    ],
                  ),
                  onTap: () {
                    setState(() {
                      flag = !flag;
                    });
                  },
                ),
              ],
            ),
    );
  }
}

Upvotes: 74

G&#252;nter Z&#246;chbauer
G&#252;nter Z&#246;chbauer

Reputation: 657871

A simple example

class ExpandableText extends StatefulWidget {
  ExpandableText(this.text);

  final String text;
  bool isExpanded = false;

  @override
  _ExpandableTextState createState() => new _ExpandableTextState();
}

class _ExpandableTextState extends State<ExpandableText> {
  @override
  Widget build(BuildContext context) {
    return new Column(children: <Widget>[
      new ConstrainedBox(
          constraints: widget.isExpanded
              ? new BoxConstraints()
              : new BoxConstraints(maxHeight: 50.0),
          child: new Text(
            widget.text,
            softWrap: true,
            overflow: TextOverflow.fade,
          )),
      widget.isExpanded
          ? new Container()
          : new FlatButton(
              child: const Text('...'),
              onPressed: () => setState(() => widget.isExpanded = true))
    ]);
  }
}

with animation

class ExpandableText extends StatefulWidget {
  ExpandableText(this.text);

  final String text;
  bool isExpanded = false;

  @override
  _ExpandableTextState createState() => new _ExpandableTextState();
}

class _ExpandableTextState extends State<ExpandableText>
    with TickerProviderStateMixin<ExpandableText> {
  @override
  Widget build(BuildContext context) {
    return new Column(children: <Widget>[
      new AnimatedSize(
          vsync: this,
          duration: const Duration(milliseconds: 500),
          child: new ConstrainedBox(
              constraints: widget.isExpanded
                  ? new BoxConstraints()
                  : new BoxConstraints(maxHeight: 50.0),
              child: new Text(
                widget.text,
                softWrap: true,
                overflow: TextOverflow.fade,
              ))),
      widget.isExpanded
          ? new ConstrainedBox(constraints: new BoxConstraints())
          : new FlatButton(
          child: const Text('...'),
          onPressed: () => setState(() => widget.isExpanded = true))
    ]);
  }
}

Upvotes: 34

Related Questions