0

Basically I want to achieve exactly the same thing as Flutter: How to hide or show more text within certain length. Here is my code snippet.

LayoutBuilder(
                  builder: (BuildContext context, BoxConstraints constraints) {
                final TextSpan span = TextSpan(
                  text: text,
                  style: TextStyle(
                    fontSize: 13,
                  ),
                );
                final TextPainter textPainter = TextPainter(
                  text: span,
                  maxLines: 1,
                  ellipsis: '...',
                  textDirection: TextDirection.ltr,
                );
                textPainter.layout(maxWidth: constraints.maxWidth);

                if (textPainter.didExceedMaxLines)
                  return Row(
                    crossAxisAlignment: _basicInformationIsExpanded
                        ? CrossAxisAlignment.end
                        : CrossAxisAlignment.start,
                    children: <Widget>[
                      Expanded(
                        child: Text(
                          text,
                          style: TextStyle(
                            fontSize: 13,
                          ),
                          maxLines: _isExpanded ? null : 1,
                          //overflow: TextOverflow.ellipsis,
                        ),
                      ),
                      GestureDetector(
                        child: _isExpanded
                            ? Icon(
                                Icons.expand_less,
                              )
                            : Icon(
                                Icons.expand_more,
                              ),
                        onTap: () {
                          setState(() => _isExpanded =
                              !_isExpanded);
                        },
                      ),
                    ],
                  );
                else
                  return Text(
                    text,
                    style: TextStyle(
                      fontSize: 13,
                    ),
                  );
              }),

The weird thing is if I comment overflow: TextOverflow.ellipsis,, everything is fine. But I need to show the ellipsis and if I add that line, the text doesn't expand when I click the icon.

Can anyone help me with it? Thanks.

5
  • remove the expanded Commented Aug 27, 2020 at 2:50
  • @Uni Removing the expanded causes overflow on the right :( Commented Aug 27, 2020 at 3:00
  • even if you uncomment textoverflow? Commented Aug 27, 2020 at 3:12
  • @Uni Yeah. I referred to this post medium.com/@VasyaFromRussia/… and this stackoverflow.com/questions/54091055/… but I couldn't figure out why my code didn't work. Commented Aug 27, 2020 at 3:27
  • Sorry, I really don't know why its not working. Commented Aug 27, 2020 at 3:31

3 Answers 3

2

You can copy paste run full code below
You can set overflow based on _isExpanded

overflow: _isExpanded ? null : TextOverflow.ellipsis,

working demo

enter image description here

full code

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

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

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Container(
                width: 200,
                child: ExpandText(
                  text: "long string" * 10,
                )),

          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

class ExpandText extends StatefulWidget {
  String text;
  ExpandText({this.text});
  @override
  _ExpandTextState createState() => _ExpandTextState();
}

class _ExpandTextState extends State<ExpandText> {
  bool _isExpanded = false;
  bool _basicInformationIsExpanded = true;

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
        builder: (BuildContext context, BoxConstraints constraints) {
      final TextSpan span = TextSpan(
        text: widget.text,
        style: TextStyle(
          fontSize: 13,
        ),
      );
      final TextPainter textPainter = TextPainter(
        text: span,
        maxLines: 1,
        ellipsis: '...',
        textDirection: TextDirection.ltr,
      );
      textPainter.layout(maxWidth: constraints.maxWidth);

      if (textPainter.didExceedMaxLines) {
        print("exceed");
        return Row(
          crossAxisAlignment: _basicInformationIsExpanded
              ? CrossAxisAlignment.end
              : CrossAxisAlignment.start,
          children: <Widget>[
            Expanded(
              flex: 1,
              child: Text(
                widget.text,
                style: TextStyle(
                  fontSize: 13,
                ),
                maxLines: _isExpanded ? null : 1,
                overflow: _isExpanded ? null : TextOverflow.ellipsis,
              ),
            ),
            GestureDetector(
              child: _isExpanded
                  ? Icon(
                      Icons.expand_less,
                    )
                  : Icon(
                      Icons.expand_more,
                    ),
              onTap: () {
                setState(() => _isExpanded = !_isExpanded);
              },
            ),
          ],
        );
      } else {
        print("not exceed");
        return Text(
          widget.text,
          style: TextStyle(
            fontSize: 13,
          ),
        );
      }
    });
  }
}
Sign up to request clarification or add additional context in comments.

Comments

0

A long ago i stumbled onto same thing, surely using these widget's is a way to do this, but here is the code which i wrote and its totally customizable.

You can change the limit variable to use it accordinly

class QNAContainer extends StatefulWidget {
  final String ques;
  final String answer;
  QNAContainer({@required this.ques, @required this.answer});
  @override
  _QNAContainerState createState() => _QNAContainerState();
}

class _QNAContainerState extends State<QNAContainer> {
  String truncAns;
  bool showingAll = false;
  int limit = 80;
  @override
  void initState() {
    super.initState();
    if (widget.answer.length > limit ) {
      print("truncc");
      truncAns = widget.answer.toString().substring(0, limit) + '...';
    } else {
      truncAns = widget.answer;
    }
  }

  @override
  Widget build(BuildContext context) {
    ScreenUtil.instance = ScreenUtil(
        width: Styles.get_width(context),
        height: Styles.get_height(context),
        allowFontScaling: true);
    return Container(
      width: double.infinity,
      padding: EdgeInsets.symmetric(horizontal: ScreenUtil().setWidth(10), vertical: ScreenUtil().setHeight(10)),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(5),
        color: AppColors.greyFillColor.withOpacity(0.6),
      ),
      margin: EdgeInsets.symmetric(vertical: ScreenUtil().setHeight(7)),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Text(widget.ques,
              style: TextStyle(
                fontSize: ScreenUtil().setHeight(14),
                fontWeight: FontWeight.bold,
              )),
          SizedBox(height: ScreenUtil().setHeight(5)),
          Text(showingAll ? widget.answer : truncAns,
              style: TextStyle(
                fontSize: ScreenUtil().setHeight(14),
              )),
          SizedBox(height: ScreenUtil().setHeight(5)),
          truncAns.contains('...')
              ? GestureDetector(
                  onTap: () {
                    setState(() {
                      showingAll = !showingAll;
                    });
                  },
                  child: Align(
                    alignment: Alignment.centerRight,
                    child: Container(
                      margin: EdgeInsets.only(bottom: ScreenUtil().setHeight(5)),
                      padding: EdgeInsets.symmetric(vertical: ScreenUtil().setHeight(5), horizontal: ScreenUtil().setWidth(9)),
                      decoration: BoxDecoration(
                          borderRadius: BorderRadius.circular(10),
                          color: AppColors.kDefaultPink),
                      child: Text(
                        showingAll ? 'see less' : 'see more',
                        style: TextStyle(color: Colors.white, fontSize: ScreenUtil().setHeight(14)),
                      ),
                    ),
                  ),
                )
              : SizedBox()
        ],
      ),
    );
  }
}

Comments

0

You can configure the overflow as you like... and from how many lines you want the view more button to appear.

Component demo:

Demo text exapanded

Code:Example

class AppExpandableText extends StatefulWidget {
  final String text;
  final TextStyle? style;
  final int trimLines;

  const AppExpandableText({
    super.key,
    required this.text,
    this.style,
    this.trimLines = 3,
  });

  @override
  State<AppExpandableText> createState() => _AppExpandableTextState();
}

class _AppExpandableTextState extends State<AppExpandableText> {
  bool _expanded = false;
  bool _isOverflowing = false;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    WidgetsBinding.instance.addPostFrameCallback((_) => _checkOverflow());
  }

  void _checkOverflow() {
    final span = TextSpan(text: widget.text, style: widget.style);
    final tp = TextPainter(
      text: span,
      maxLines: widget.trimLines,
      textDirection: TextDirection.ltr,
    )..layout(maxWidth: MediaQuery.of(context).size.width);

    setState(() {
      _isOverflowing = tp.didExceedMaxLines;
    });
  }

  @override
  Widget build(BuildContext context) {
    
    final textWidget = Text(
      widget.text,
      style: widget.style,
      maxLines: _expanded ? null : widget.trimLines,
      overflow: _expanded ? TextOverflow.visible : TextOverflow.clip,
    );

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      mainAxisSize: MainAxisSize.min,
      children: [
        textWidget,
        if (_isOverflowing)
          InkWell(
            onTap: () => setState(() => _expanded = !_expanded),
            child: Text(
              _expanded ? '...Ver menos' : '...Ver más',
              style: widget.style,
            ),
          ),
      ],
    );
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.