30

TextDirection文档说:

Flutter 旨在满足使用世界上任何一种当前使用的语言编写的应用程序的需求,无论它们使用从右到左还是从左到右的书写方向。Flutter 不支持其他书写模式,例如竖排文本或 boustrophedon 文本,因为这些在计算机程序中很少使用。(重点补充)

Flutter 不仅不支持竖排文本,未来也不会正式支持。这是一个早期的设计决定(参见此处此处)。

即便如此,如今垂直脚本支持仍有实际用途。除了某些中文和日文用途外,传统的蒙古文字也需要它。该脚本在内蒙古的计算机程序中非常常用(示例示例示例示例示例示例)。

它是从上到下写的,从左到右换行:

在此处输入图像描述

此外,表情符号和 CJK 字符在垂直显示时保持其方向(不是绝对必要,但首选)。在下图中,顶部段落显示了当前的实现,底部段落显示了正确的垂直渲染:

在此处输入图像描述

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

由于 Flutter 不支持垂直脚本,所以必须从头开始实现。所有实际的文本布局和绘画都是在 Flutter 引擎中使用LibTxt完成的,所以我无法更改。

创建一个从上到下的垂直文本小部件会涉及什么?

更新

我还在寻找答案。Rémi 的答案适用于单行文本,但不适用于多行文本。

我目前正在研究三种不同的可能解决方案:

  • 创建一个支持类似于 RichText 小部件的自定义 StatelessWidget的 RenderObject 子类(或者可能是RenderParagraph子类)。
  • 使用 CustomPaint 小部件
  • 制作 ListView(每行一行)、Text 小部件和 WidgetSpan 的复合小部件。

所有这些都涉及测量文本、布置文本并获取行列表。

另一个更新

我目前倾向于制作一个自定义小部件和渲染对象,以模仿 RichText 和 RenderParagraph。在底层 RenderParagraph 使用 TextPainter 来布局和绘制文本。我现在的问题是 TextPainter 与底层的 Skia LibTxt 库紧密耦合。那是所有实际布局和绘画发生的地方。在默认的 ltr 和 rtl 之外的任何地方布置文本被证明是一个大问题。

又一次更新

接受的答案符合我在这个问题中提出的标准。我认为这将满足短期需求。我对应用文本样式之类的事情有一些保留,但我需要做更多的测试。从长远来看,我可能仍会尝试自定义文本布局和绘画。

4

6 回答 6

35

可以使用横向文本RotatedBox,这足以使文本按照您的预期正确换行。

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

在此处输入图像描述

同样,Flutter 现在支持文本内的内联小部件。这可用于在文本中旋转笑脸。

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

在此处输入图像描述

于 2019-07-02T08:53:44.813 回答
24

该解决方案基于弹性盒布局。它将字符串转换为单词列表并将它们放入垂直旋转的文本小部件中。这些布局与Wrap设置为的小部件Axis.vertical。Wrap 小部件通过将它们放在下一列中来自动处理需要换行的单词。

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's 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;
  }
}

在此处输入图像描述

于 2019-07-08T15:38:49.647 回答
6

使用很简单RotatedBox

RotatedBox(
  quarterTurns: 1,
  child: //your text
),

于 2021-06-07T10:14:20.540 回答
2

如果您使用所有符号旋转 180°(硬部分)制作自定义字体,那么您可以简单地将textDirection更改为TextDirection.rtl(从右到左)并将文本旋转四分之一(也不容易)。

于 2019-07-06T11:46:30.053 回答
1

我最终创建了一个自定义小部件来处理文本渲染。

在此处输入图像描述

这不是一项简单的任务,但它是灵活的。如果其他答案不能满足您的需求,则此问题的其他访问者可以遵循类似的模式。

如果您想更好地控制 Flutter 中的文本渲染,请阅读我对 Flutter 的第一次失望,并在此 GitHub 问题中添加评论。

于 2020-02-11T00:52:23.440 回答
-1

它的简单画出你想要的

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<--------------
)
于 2019-07-08T11:19:37.167 回答