preface

The Text in Flutter has always been a bit disappointing, and people often compare it to the native platform,

Why alipay, wechat, but not Flutter? Flutter spicy chicken.

When will Flutter stand up?

Text overflow (ellipsis) cannot be customized

Text overflow (ellipses) can not custom, ExtendedText has to solve the problem, you can use the Settings ExtendedText. OverflowWidget define any overflow from the content.

    ExtendedText(
      overflowWidget: TextOverflowWidget(
        align: TextOverflowAlign.center,
        child: Container(
          child: Row(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              const Text(
                '\u2026 ',
                style: TextStyle(height: 1),
              ),
              InkWell(
                child: Image.asset(
                  'assets/candies.png',
                  width: 20,
                  height: 20,
                ),
                onTap: () {
                  launch('https://github.com/fluttercandies/extended_text');
                },
              )
            ],
          ),
        ),
      ),
    );
Copy the code

Unable to specify text overflow (ellipsis) location

There is no way to specify the location of text overflow (ellipsis), as in the following two common scenarios.

  1. The ellipsis is in the middle

  1. The ellipsis comes first

Flutter is not supported, so let’s see if it is supported native and on the Web. (Please correct me if there is anything wrong.)

platform At the beginning In the middle At the end
android android:ellipsize = "start" android:ellipsize = "middle"   android:ellipsize = "end"
Ios NSLineBreakByTruncatingHead NSLineBreakByTruncatingMiddle NSLineBreakByTruncatingTail
web text-overflow: ellipsis clip Does not support text-overflow: clip ellipsis
flutter Does not support Does not support TextOverflow.ellipsis

Android :singleline = “true”; The Web does not support the middle; Ios has the best support.

As you can see, native and Web side support for this feature is much better than Flutter. So there’s nothing we can do about Flutter? Of course not, the previous solution to text overflow (ellipsis) can not be customized, the same principle can be applied to this feature, below is the final image.

The principle of

performLayout

In the performLayout method, TextPainter goes through the layout to see if the current text is overflowing.

    final Size textSize = _textPainter.size;
    final bool textDidExceedMaxLines = _textPainter.didExceedMaxLines;
    size = constraints.constrain(textSize);

    final bool didOverflowHeight = size.height < textSize.height || textDidExceedMaxLines;
    final bool didOverflowWidth = size.width < textSize.width;
    // TODO(abarth): We're only measuring the sizes of the line boxes here. If
    // the glyphs draw outside the line boxes, we might think that there isn't
    // visual overflow when there actually is visual overflow. This can become
    // a problem if we start having horizontal overflow and introduce a clip
    // that affects the actual (but undetected) vertical overflow.
    final bool hasVisualOverflow = didOverflowWidth || didOverflowHeight;

Copy the code

Calculate the case without overflow

And again, we’re going to rely on TextPainter, by binary search, to find the point X that doesn’t overflow.

At the beginning In the middle At the end
[0,X] [m,X].mIs the index position of the intermediate text The text doesn’t need to be changed, it doesn’t need to be computed

Text within this Range will not be displayed.

Handling text

For example, abcdef, we find a Range of [2,3], which finally shows ab… Ef. Consider supporting selective copying, so we can’t simply drop the CD here. So we’re taking advantage of one of the functions of SpecialTextSpan.

What you see is not real

 SpecialTextSpan(
   'abef',
   actualText: 'abcdef',);Copy the code

Overflow content drawing

At the beginning In the middle At the end
Draw at the beginning of the text Draw it in the middle of the text Draw at the end of the text

In fact, what we’re going to do is draw the overflow at these locations and blot out the text below. And to do that,

  1. According to theRangeTo obtainTextSelection, the use ofTextPainter.getBoxesForSelectionGets the area of the paragraph masking the textoverflowRect
  2. withoverflowRectUnion with the size of the overflow.
  3. mobileRangeI’m going to keep taking the union until IoverflowRectIt’s totally inclusive of the size of the overflow. (Make sure overflow content is displayed and shaded text is not exposed)

The code is in the _setOverflowRect method.

Covered writing

In previous versions, Paint().. BlendMode = blendmode. clear cannot clear the text, so we have to use Canvas.clippath (path) to crop out the text in the overflowRect part. Now that the problem has been officially fixed, you can do just that. (The actual small partners often mentioned do not know how to do the camera mask, in fact, you can use this method, the mask to dig a hole.)

    if(_overflowRect ! =null) {
      context.canvas.saveLayer(_offset & size, Paint());
    }
    // Draw text
    _paint(context, offset);
    if(_overflowRect ! =null) {
      // Clear the text in this areacontext.canvas.drawRect( _overflowRect! .shift(_offset), Paint().. blendMode = BlendMode.clear); context.canvas.restore(); }Copy the code

More details

In fact, the above is just a general idea, which involves a lot of calculations, if you are interested, you can look at this file.

disadvantages

  • usingTextPainterTo achieve the final calculation,TextPainterThere are a lot of limitations, like rightWidgetSpanSome of the calculation errors, though, have been exploitedworkaroundTo get around it. However, every change to the official engine can have an impact on the result.
  • Across themiddleIn this case, if the height of each line of text is too different, the calculation will probably fail,TextPainterDid not provide oneapiTo tell us the information directly.

Line breaks and overflow are not friendly

Line breaks and overflow are not friendly, such as displaying the following paragraph in a Flutter.

Your candy service has been renewed, service order number: 12345678910987654321110.

reality expect

This problem is also not unique to Flutter, but relates to the handling of Word typesetting. Insert zero-width space(\u{200B}) into the text.

Characters('abc').join('\u{200B}');
Copy the code

Of course you can directly to ExtendedText. JoinZeroWidthSpace set to true.

  ExtendedText(
      joinZeroWidthSpace: true.)Copy the code

Or you can take advantage of the extension methods in the ExtendedTextLibrary.

  1. The text
  String input='abc'.joinChar('\u{200B}');
Copy the code
  1. InlineSpan
    InlineSpan innerTextSpan;
     innerTextSpan = joinChar(
        innerTextSpan,
        Accumulator(),
        '\u{200B}',);Copy the code

But you need to be aware of the following:

  1. Word is no longer Word and you will not be able to select Word by double-clicking.

  2. Text is modified, if ExtendedText selectionEnabled is true, you need to rewrite TextSelectionControls handleCopy, Discard zero-width space(\u{200B}).


class MyTextSelectionControls extends TextSelectionControls {

  @override
  void handleCopy(TextSelectionDelegate delegate,
      ClipboardStatusNotifier? clipboardStatus) {
    final TextEditingValue value = delegate.textEditingValue;

    String data = value.selection.textInside(value.text);
    // remove zeroWidthSpace
    data = data.replaceAll('\u{200B}'.' ');

    Clipboard.setData(ClipboardData(
      text: value.selection.textInside(value.text),
    ));
    clipboardStatus?.update();
    delegate.textEditingValue = TextEditingValue(
      text: value.text,
      selection: TextSelection.collapsed(offset: value.selection.end),
    );
    delegate.bringIntoView(delegate.textEditingValue.selection.extent);
    delegate.hideToolbar();
  }
}

Copy the code

The final result is shown below, and you can see that the text is much more compact.

conclusion

ExtendedText isn’t perfect, but it should work. Sometimes, an idea can only come true when it is realized. When the idea is confirmed step by step in the brain, it is left to practice, from the simplest scene to the complex scene, down-to-earth, isn’t it the same with being a person?

loveFlutterLove,candyWelcome to join usFlutter CandiesTogether to make cute little Flutter candiesQQ group: 181398081

And finally, put Flutter Candies on it. It smells sweet.