Вертикальный текстовый виджет для флаттера - программирование
Подтвердить что ты не робот

Вертикальный текстовый виджет для флаттера

Документы TextDirection говорят:

Flutter предназначен для удовлетворения потребностей приложений, написанных на любом из используемых в настоящее время языков мира, независимо от того, используют ли они направление письма справа налево или слева направо. Flutter не поддерживает другие режимы письма, такие как вертикальный текст или бустрофедон, так как они редко используются в компьютерных программах. (выделение добавлено)

Flutter не только не поддерживает вертикальный текст, но и не будет официально поддерживаться в будущем. Это было раннее дизайнерское решение (см. Здесь и здесь).

Тем не менее, сегодня существует реальная поддержка вертикального сценария. В дополнение к определенному китайскому и японскому использованию, это требуется традиционному монгольскому письму. Этот сценарий очень часто используются в компьютерных программах во Внутренней Монголии (пример, пример, пример, пример, пример, пример).

Это написано сверху вниз, и строки переносятся слева направо:

enter image description here

Кроме того, символы эмодзи и CJK сохраняют свою ориентацию при вертикальном отображении (не обязательно, но желательно). На изображении ниже верхний абзац показывает текущую реализацию, а нижний абзац показывает правильную вертикальную визуализацию:

enter image description here

// sample text
ᠨᠢᠭᠡ ᠬᠣᠶᠠᠷ ᠭᠣᠷᠪᠠ ᠳᠥᠷᠪᠡ ᠲᠠᠪᠤ ᠵᠢᠷᠭᠤᠭ᠎ᠠ ᠳᠣᠯᠣᠭ᠎ᠠ ᠨᠠ‍ᠢᠮᠠ ᠶᠢᠰᠦ ᠠᠷᠪᠠ one two three four five six seven eight nine ten 😃🐐汉字 한국어 モンゴル語 English? ᠮᠣᠩᠭᠣᠯ︖

Поскольку Flutter не поддерживает вертикальный скрипт, он должен быть реализован с нуля. Все фактическое расположение текста и рисование выполняется в движке Flutter с LibTxt, поэтому я не могу этого изменить.

Что потребуется для создания вертикального текстового виджета сверху вниз?

Обновить

Я все еще ищу ответ. Ответ Реми хорош для однострочного текста, но не работает для многострочного текста.

В настоящее время я исследую три различных возможных решения:

  • Создайте подкласс RenderObject (или, возможно, подкласс RenderParagraph), который поддерживает пользовательский StatelessWidget, похожий на виджет RichText.
  • Используйте виджет CustomPaint
  • Создайте составной виджет для ListView (одна строка на текстовую строку), текстовых виджетов и WidgetSpans.

Все это включает измерение текста, его разметку и получение списка строк.

Еще одно обновление

В настоящее время я склоняюсь к созданию собственного виджета и визуализации объекта, который будет имитировать RichText и RenderParagraph. Под капотом RenderParagraph использует TextPainter для разметки и рисования текста. Моя проблема сейчас в том, что TextPainter тесно связан с базовой библиотекой Skia LibTxt. Вот где происходит вся фактическая планировка и покраска. Выкладывание текста во что угодно, кроме ltr и rtl по умолчанию, оказывается большой проблемой.

Еще одно обновление

Принятый ответ соответствует критериям, изложенным в этом вопросе. Я думаю, что это будет отвечать краткосрочным потребностям. У меня есть некоторые оговорки для таких вещей, как применение стиля текста, но мне нужно будет сделать больше тестов. В долгосрочной перспективе я все еще могу попытаться сделать нестандартную разметку текста и рисование.

4b9b3361

Ответ 1

Это решение основано на компоновке flex-box. Он преобразует строку в список слов и помещает их в вертикально повернутые текстовые виджеты. Они размещаются с виджетом Wrap установленным в Axis.vertical. Виджет Обтекание автоматически обрабатывает слова, которые необходимо обернуть, помещая их в следующий столбец.

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Wrap(
          direction: Axis.vertical,
          children: _getWords(),
        ),
      ),
    );
  }

  List<Widget> _getWords() {
    const text =
        "That all 😉🐐 12345 One Two Three Four Five ᠸᠢᠺᠢᠫᠧᠳᠢᠶᠠ᠂ ᠴᠢᠯᠦᠭᠡᠲᠦ ᠨᠡᠪᠲᠡᠷᠬᠡᠢ ᠲᠣᠯᠢ ᠪᠢᠴᠢᠭ ᠪᠣᠯᠠᠢ᠃";
    var emoji = RegExp(r"([\u2200-\u3300]|[\uD83C-\uD83E].)");
    List<Widget> res = [];
    var words = text.split(" ");
    for (var word in words) {
      var matches = emoji.allMatches(word);
      if (matches.isEmpty) {
        res.add(RotatedBox(quarterTurns: 1, child: Text(word + ' ')));
      } else {
        var parts = word.split(emoji);
        int i = 0;
        for (Match m in matches) {
          res.add(RotatedBox(quarterTurns: 1, child: Text(parts[i++])));
          res.add(Text(m.group(0)));
        }
        res.add(RotatedBox(quarterTurns: 1, child: Text(parts[i] + ' ')));
      }
    }
    return res;
  }
}

enter image description here

Ответ 2

Боковой текст возможен с помощью RotatedBox, что достаточно для правильной переноски текста, как вы ожидаете.

Row(
  children: <Widget>[
    RotatedBox(
      quarterTurns: 1,
      child: Text(sample),
    ),
    Expanded(child: Text(sample)),
    RotatedBox(
      quarterTurns: -1,
      child: Text(sample),
    ),
  ],
),

enter image description here

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

RotatedBox(
  quarterTurns: 1,
  child: RichText(
    text: TextSpan(
      text: 'Hello World',
      style: DefaultTextStyle.of(context).style,
      children: [
        WidgetSpan(
          child: RotatedBox(quarterTurns: -1, child: Text('😃')),
        )
      ],
    ),
  ),
),

enter image description here

Ответ 3

Если вы делаете собственный шрифт со всеми символами, повернутыми на 180 ° (сложная часть), то вы можете просто изменить textDirection на TextDirection.rtl (справа налево) и повернуть текст на одну четверть (это тоже не легко).

Ответ 4

Это просто нарисовать то, что вы хотите

Примеры flutter-widget-positioning-guide

затем

Column(
    children: [
        MyWidget(),
        MyWidget(),
        MyWidget()
    ]
);

// or swap a Column for a Row to flip the axis

Row(children: [ ]);

// and this is all just sugar for the Flex widget
Flex(
    direction: Axis.vertical<--------------
)