Что на самом деле делает Paragraph.getBoxesForRange в Flutter

#flutter #dart #text #text-rendering

#flutter #dart #текст #текстовый рендеринг

Вопрос:

Класс Paragraph в Flutter имеет вызываемый метод getBoxesForRange .

В документации говорится:

Возвращает список текстовых полей, которые заключают заданный текстовый диапазон.

Однако мне неясно, являются ли поля полями вокруг строк текста, которые включают данный диапазон, или если они являются чем-то другим.

После дальнейших исследований я нашел ответ, который я добавляю ниже.

Ответ №1:

Короткий ответ

Paragraph.getBoxesForRange дает вам то, что по сути было бы выделенной областью для данного диапазона, если бы оно было выбрано. Вы получаете более одного поля, если диапазон переносится на новую строку (или если он содержит смешанный двунаправленный текст).

Более длинный ответ

Учитывая строку:

 Hello, world.
 

Если вы берете диапазон от 1 до 8 примерно так:

 final boxes = paragraph.getBoxesForRange(1, 8);
 

Это даст вам одно поле:

 [
  TextBox.fromLTRBD(22.3, -0.3, 112.0, 35.0, TextDirection.ltr)
]
 

Графически это будет выглядеть так:

введите описание изображения здесь

Это показывает, что поля не являются полными строками, а только переносят указанный диапазон текста.

Если вы ограничите ширину так, чтобы абзац был вынужден переносить текст в строку, вы получите следующее:

введите описание изображения здесь

 [
  TextBox.fromLTRBD(22.3, -0.3, 47.0, 35.0, TextDirection.ltr), 
  TextBox.fromLTRBD(0.0, 34.7, 41.8, 70.0, TextDirection.ltr), 
  TextBox.fromLTRBD(0.0, 69.7, 23.2, 105.0, TextDirection.ltr)
]
 

Полный код

Вот полный код, если вы хотите поиграть с ним самостоятельно.

 import 'package:flutter/material.dart';
import 'dart:ui' as ui;

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: HomeWidget(),
      ),
    );
  }
}

class HomeWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: CustomPaint(
        size: Size(300, 300),
        painter: MyPainter(),
      ),
    );
  }
}

class MyPainter extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final textStyle = ui.TextStyle(
      color: Colors.black,
      fontSize: 30,
    );
    final paragraphStyle = ui.ParagraphStyle(
      textDirection: TextDirection.ltr,
    );
    final paragraphBuilder = ui.ParagraphBuilder(paragraphStyle)
      ..pushStyle(textStyle)
      ..addText('Hello, world.');
    final constraints = ui.ParagraphConstraints(width: 300);
    // final constraints = ui.ParagraphConstraints(width: 50);
    final paragraph = paragraphBuilder.build();
    paragraph.layout(constraints);
    canvas.drawParagraph(paragraph, Offset.zero);

    final boxes = paragraph.getBoxesForRange(1, 8);
    print(boxes);
    final paint = Paint()
      ..color = Colors.blue
      ..style = PaintingStyle.stroke
      ..strokeWidth = 1;
    for (final box in boxes) {
      final rect = Rect.fromLTRB(box.left, box.top, box.right, box.bottom);
      canvas.drawRect(rect, paint);
    }
  }

  @override
  bool shouldRepaint(CustomPainter old) {
    return false;
  }
}