Flutter-VerticalText

需求

今天有人问了我一个很有意思的问题:如何实现文字竖直排列,就像古诗词一样。

思路

我首先想到的是使用 Container 组件嵌套 Text 组件,固定它的宽度,这样来实现一行一个文字。看起来就像竖直排列一样。但是它的文字垂直间距很显然不方便控制。

我便去 StackOverflow 上搜索了一番 vertical text。果然有所收获。有人提出,使用 Wrap 组件去实现这个功能。分割需要竖直排列的字符串为单个字,用 Text 组件包裹每个字,然后利用 Wrap 组件的 direction 使得这些 Text 列表垂直排列,排不下则往右边另起一列。

我自然是希望古诗一列一句的。所以就不用考虑超出换列,手动分割当然最好。既然使用不到 Wrap ,用各种 ListView 来展示上面的 Text 们也是可以的。

当然了,如果是显示的宋词,那一句太长也是有可能的,为了保险起见,我还是使用了Wrap做了超出处理。

如此一来,就可以着手实现了。封装一个用 Wrap 为核心的自定义组件,主要用于展示古诗的一句。我们拿到一个古诗后,可以将古诗按标点符号分割,分割后的句子用自定义的 VerticalText 显示就可以了。我更倾向于用 Row 组件去显示,因为我能用它决定主轴方向和交叉轴方向的起点,这能做到古诗句的上对齐,和右对齐。用 ListView 的话,可以很方便地翻转古诗句的顺序,但是不太方便对齐。

具体的实现可以参考如下代码。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
import 'package:flutter/material.dart';

class MyPage extends StatelessWidget {
const MyPage({super.key});

@override
Widget build(BuildContext context) {
List<VerticalText> poetry=const[
VerticalText("将进酒,"),
VerticalText("杯莫停。"),
VerticalText("与君歌一曲,"),
VerticalText("请君为我倾耳听。")
];
return Scaffold(
appBar: AppBar(
title: const Text("test"),
),
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.start,
children: List.from(poetry.reversed) ,
),
),
);
}
}

class VerticalText extends StatelessWidget {
final String text;
const VerticalText(this.text,{Key? key}) : super(key: key);

@override
Widget build(BuildContext context) {
//分割字符串为单字,每个字包裹一个Text组件,作为Wrap组件的子组件
List<Text> texts=text.split("").map((string) => Text(string, style: const TextStyle(fontSize: 17))).toList();
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 10),
child: Wrap(
//排列方式,vertical代表竖着排,排不够就往旁边排
direction: Axis.vertical,
//主轴方向上间距
spacing: 20,
//交叉轴方向上间距
runSpacing: 30,
alignment: WrapAlignment.center,
children: texts,
),
);
}
}

效果图