了解 Unicode 在 Flutter 上的展示
以前我对 emoji
是一头雾水,尤其是接入微信登录时,对于名字带表情的都是简单过滤处理,很暴力不是,我也试了好几次像支持 emoji
,单奈何就是不行,今天看到了有关文章,总结了下,总算是清楚了,去了我一块心病,对于 emoji
不清楚的同学可以试试看,也许对你有帮助
emoji
其实就是 Unicode 16进制编码~
Unicode 简介
Unicode
编码是国际最通用的字符编码了,Unicode
里给不同语言的每个字符,其他各种符号,包括 emoji 表情都设置有自己独立的编号,所以就不会再出现乱的问题了,但是随着各种符号越来越多,尤其是 emoji 表情大行其道之后,这符号的数量与日俱增,为了装的下这么多符号,目前 Unicode 最多已经采用到 32位来存储了
-
UTF-8
- 占用一到四个字节,主要用来存储英文系字符 -
UTF-16
- 占用二或四个字节,主要存储世界上所有文字 -
UTF-32
- 占用四个字节,主要方 emoji 表情这种
UTF 有好几种,不是说只用最大编码的,不同的系统根据实际需求会选择自己默认支持的 UTF,一般文字的话 UTF-8 就足够了,但是处理 emoji 就得 UTF-32 了,具体在于使用场景
Unicode 储存图
UTF-32 储存值从 U+0000
到 U+10FFFF
,分成14个扇区存储,每一个扇区有 256 个小块,每个小块有 16×16 = 256 个编码点,总体下来每个扇区有 65536 个 编码点
扇区图:没一个大块就是一个扇区
image
不同语言的字符,包括古今文字,上古语言,符号,emoji 都存储在不同的扇区内
- Unicode 0 号平面(0000-FFFF)
- Unicode 1 号平面(10000-1FFFF)
Unicode 所有的字符可以在官方网站上查询到:
所以这 Unicode 数值也挺乱的,大家要注意,对于不同的数值范围 Dart 中有不同的保存格式:
-
\u2665
- 4个16进制的数的这么写 -
\u{1f600}
- 但要不是4位的就得在数值前加{}
了
Flutter 上显示 emoji
Flutter 上想要正确显示 emoji 表情,请示就是给不同数值范围的 Unicode 编码套整个的格式
显示单个 emoji
var index = "\u{1f44f}";
image
显示多个,带文字混排
Runes input = new Runes(
'\u2665 \u{1f605} \u{1f60e} \u{1f47b} \u{1f596} \u{1f44d} 哇哈哈哈哈!!!');
var index = String.fromCharCodes(input);
image
Dart 字符编码的 API
Dart 上又一个接受 UTF-32 编码的类:Runes
,可以把 UTF-32 处理成能是别的 10进制数据
Dart 文字显示默认是 UTF-16 的,我们兼容 emoji 的话最好用 UTF-32,必须用 Runes
这个类,Runes
可以让我们按照 UTF-32 存储展示字符
dart:core
库提供了获取字符编码的 API:
-
String.codeUnitAt(index)
- 返回指定字符的 10 进制 Unicode 索引 -
String.codeUnits
- 返回所有字符的 10 进制 Unicode 索引,结果是个集合 -
String.runes
- 返回所有字符的 10 进制 Unicode 编码值,结果是个集合
var index1 = "我";
var index2 = "我是富翁,我老有钱了";
print("index1:${index1.codeUnitAt(0)}");
print("index1:${index2.codeUnits}");
print("index1:${index1.runes}");
I/flutter ( 6849): index1:25105
I/flutter ( 6849): index1:[25105, 26159, 23500, 32705, 65292, 25105, 32769, 26377, 38065, 20102]
I/flutter ( 6849): index1:(25105)
我详细解释下,有点绕,不容易搞清楚
例子:
Unicode 编码都是 16 进制的,通常表示为 \uXXXX
,其中这个 xxxx
就是具体的 16进制值
比如这个符号:他的 16进制 Unicode 编码是 \u2665
,2665 的 10 进制 = 9829
我们来看下:
Runes input = new Runes('\u2665');
var index = String.fromCharCodes(input);
print("index1:${index.codeUnitAt(0)}");
print("index1:${index.codeUnits}");
print("index1:${index.runes}");
I/flutter ( 6849): index1:9829
I/flutter ( 6849): index1:[9829]
I/flutter ( 6849): index1:(9829)
拿到的结果正好对的上 10进制数值,我们转成 16进制加上 \u
就是 Unicode 编码了
-
16 进制
Unicode 编码显示,使用Runes
类包裹数据
Runes input = new Runes('\u2665');
var index = String.fromCharCodes(input);
-
10 进制
就不用Runes
了,直接走
var index = String.fromCharCode(9829);