Flutter的垂直文本小部件

时间:2019-06-27 01:30:02

标签: flutter dart custom-widgets mongolian-vertical-script

TextDirection文档说:

  

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

Flutter不仅不支持垂直文本,将来也不会正式支持它。这是一个早期的设计决策(请参见herehere)。

即使如此,今天对垂直脚本的支持还是有实际用途的。除了某些Chinese and Japanese用途之外,traditional Mongolian script还需要它。内蒙古的计算机程序(exampleexampleexampleexampleexampleexample中非常常用的脚本。

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

enter image description here

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

enter image description here

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

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

创建顶部到底部垂直文本小部件会涉及什么?

更新

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

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

  • 创建一个RenderObject子类(或者也许是RenderParagraph子类),以支持类似于RichText小部件的自定义StatelessWidget。
  • 使用CustomPaint小部件
  • 制作一个ListView(每行文本一行),Text小部件和WidgetSpans的复合小部件。

所有这些都涉及测量文本,对其进行布局并获得行列表。

另一个更新

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

又一次更新

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

6 个答案:

答案 0 :(得分:6)

可以使用RotatedBox生成Sideway文本,这足以使文本正确包装。

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

答案 1 :(得分:6)

此解决方案基于弹性盒布局。它将字符串转换为单词列表,并将其放入垂直旋转的Text小部件中。使用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'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;
  }
}

enter image description here

答案 2 :(得分:2)

如果您制作的自定义字体的所有符号都旋转了180°(硬部分),则可以将 textDirection 更改为 TextDirection.rtl (从右到左) ),然后将文本旋转四分之一(这也不容易)。

答案 3 :(得分:2)

使用很简单RotatedBox

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

答案 4 :(得分:0)

简单绘制所需内容

示例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<--------------
)

答案 5 :(得分:0)

我最终创建了一个自定义小部件来处理文本呈现。在撰写本文时,它不能正确旋转表情符号和CJK字符,但可以处理方向和换行符。

这不是一件容易的事,但它很灵活。如果其他答案不能满足您的需求,则该问题的其他访问者也可以遵循类似的模式。

如果您想进一步控制Flutter中的文本呈现,请阅读My First Disappointment with Flutter并在this GitHub issue上添加注释。