skip to Main Content

I tried to get a number of the text widget.
For example, My 2 widgets in the column are the counter widget and the text widget.
The counter widget shows the number of lines of the text widget.
I tried using TextPainter. It can count lines of text widgets but not correctly and it will get incorrect lines when this text widget stays with another widget in the same row.

My example code:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: CountTextLine(
              text:
                  'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA'),
        ),
      ),
    );
  }
}

class CountTextLine extends StatefulWidget {
  final String text;

  const CountTextLine({super.key, required this.text});

  @override
  State<CountTextLine> createState() => _CountTextLineState();
}

class _CountTextLineState extends State<CountTextLine> {
  int _count = 0;
  late final _textPainter = TextPainter(
    text: TextSpan(text: widget.text),
    maxLines: null,
    textDirection: TextDirection.ltr,
  );

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

  void _updateTextPainter(double width) {
    _textPainter.layout(maxWidth: width);
    _count = _textPainter.computeLineMetrics().length;
  }

  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        _updateTextPainter(constraints.maxWidth);
        return Column(
          children: [
            Text(_count.toString()),
            Row(
              children: [
                Container(
                  height: 200,
                  color: Colors.green,
                  child: Text('Hello My World I Am The Another Widget!!!!!'),
                ),
                Expanded(child: Text(widget.text)),
              ],
            ),
          ],
        );
      },
    );
  }
}

You can test this code on dart pad by dragging the screen size to change its screen size.

My example result:

  1. only text widget but not correctly.
    You can see this result. This result is not correct.
    How to fix this or another way to get the number of text lines? (main required).
    enter image description here
  2. have another widget stay with the text widget.
    This image shows when my page is complex. The LayoutBuilder was used for the whole page. Yes, I can use the LayoutBuilder for each Text widget to use constraints.maxWidth of Text widget width to get the number of text lines but can we not use the LayoutBuilder for each Text widget that I want to count the number of text? (optional required).
    enter image description here

2

Answers


  1. I adjusted your layout code

    return Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Container(
              height: 200,
              color: Colors.green,
              child: Text('Hello My World I Am The Another Widget!!!!!'),
            ),
            Expanded(child: LayoutBuilder(
              builder: (context, constraints) {
                _updateTextPainter(constraints.maxWidth);
                return Column(children: [
                  Text(_count.toString()),
                  Text(widget.text),
                ]);
              },
            )),
          ],
        );
    

    the result looks like this
    enter image description here

    the _count is correct

    Login or Signup to reply.
  2. It is important that you set the same wordSpacing and letterSpacing and use the LayoutBuilder directly above your text. As an example:

    
    class _CountTextLineState extends State<CountTextLine> {
      late final StreamController<String> _countStream;
      late final TextPainter _textPainter;
    
      @override
      void initState() {
        super.initState();
        _countStream = StreamController<String>.broadcast();
        _textPainter = TextPainter(
          text: TextSpan(text: widget.text, style: const TextStyle(fontSize: 20, wordSpacing: 1, letterSpacing: 0)),
          maxLines: null,
          textDirection: TextDirection.ltr,
          textWidthBasis: TextWidthBasis.longestLine,
        );
      }
    
      @override
      void dispose() {
        _countStream.close();
        super.dispose();
      }
    
      void _updateTextPainter(double width) {
        _textPainter.layout(maxWidth: width, minWidth: width);
        final metrics = _textPainter.computeLineMetrics();
    
        _countStream.add(metrics.length.toString());
      }
    
      @override
      Widget build(BuildContext context) {
        return Column(
          children: [
            StreamBuilder<String>(
                stream: _countStream.stream,
                initialData: '0',
                builder: (context, snapshot) {
                  return Text(snapshot.data!);
                }),
            Row(
              children: [
                Container(
                  height: 200,
                  color: Colors.green,
                  child: const Text('Hello My World I Am The Another Widget!!!!!'),
                ),
                Expanded(
                  child: LayoutBuilder(builder: (context, constraints) {
                    _updateTextPainter(constraints.maxWidth);
    
                    return Text(
                      widget.text,
                      style: const TextStyle(fontSize: 20, wordSpacing: 1, letterSpacing: 0),
                    );
                  }),
                ),
              ],
            ),
          ],
        );
      }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search