安卓5.0+是可以显示所有(8万多个)Unicode汉字的,本文介绍显示生僻汉字的方法,这个方法也适用于其它特殊字符。

Unicode值在0xFFFF以下的(2万多个简体、繁体)汉字早已被广泛支持,所以本文不把它们看作生僻字。
本文说的生僻字是指Unicode值在0xFFFF以上的汉字,这个范围也叫non-BMP。

可以看这篇文章了解汉字的大致分布。

主要有4个关键点:

一、需使用Android 5.0以上系统。

经过我的测试,在Android 4.3.1模拟器、4.4.2模拟器上会出现问题,而在Android 5.0.2模拟器、6.0真机、7.0模拟器上正常。

问题见本文最后部分的两张截图:附1、附2。

二、确保字符集能覆盖生僻字。

也就是在文件、数据库保存字符串时使用的字符集,应该是:GB18030、UTF-8、UTF-16、UTF-32等能支持所有Unicode字符的字符集。

注意a:不要使用GB2312、GBK或BIG5字符集,它们的范围有限,都不支持生僻字(Unicode值大于0xFFFF)。
注意b:不要在Android程序的配置xml文件里写生僻字,Android在用UTF-8解码这些xml时,支持的范围并不完整。这个bug在Android 6.0里被修复。见此帖

按如下方法把字符串读入String后,我们进入下一个关键点。

byte[] b = read_bytes_from_somewhere();
String str = new String(b, "GB18030");

三、String在处理生僻字时会使用surrogate对。

Java的String使用的是UTF-16编码。String的一个char占两个字节,能表示0~0xFFFF之间的数值范围。

于是,根据UTF-16的规则,在String里:常用字符(Unicode值小于等于0xFFFF)用一个char表示;剩下的字符(Unicode值大于0xFFFF)用两个char组合表示,这两个char叫surrogate对儿。所以我们的生僻字符须要用两个char组合表示

surrogate对的原理是:两个char各有一个保留区域,这个保留区域有1,024个位置,于是1,024x1,024等于1,048,576,再加上单个char包含的字符,正好能覆盖Unicode所有的1,114,112个位置点。

在这里,搞清楚两个概念就可以了:

  1. char,一个char就是一个两字节整数。它是String的最小单位,一个String包含0个或若干个char。String对象的length()函数返回的就是char的个数。
  2. code point,一个code point就是一个Unicode字符,一个实际的字符。在String里,它可能用1个char表示,也可能用2个char组合表示,没有第三种可能。

所以,在处理生僻字时,String的length()函数的返回值可能大于实际字符数,想知道String的实际字符数可以用codePointCount()函数。同理,charAt()等基于char操作的函数可能也不再适用。

四、使用支持生僻字的字体。

就算程序内在支持生僻字,字体不支持也显示不出来。包括默认字体在内的很多字体都不支持生僻字。
我们可以找一个支持生僻字的字体,然后放到程序的资源目录里,指定程序使用它而不是系统的默认字体。

先找一个支持生僻字的字体,比如这个开心宋体:帖子网盘

然后按以下方法使用该字体就可以了(出处):

//得到TextView控件对象
TextView textView = (TextView) findViewById(R.id.custom); //将字体文件保存在assets/fonts/目录下,创建Typeface对象
Typeface typeFace = Typeface.createFromAsset(getAssets(), "fonts/KaiXinSong.ttf"); //使用字体
textView.setTypeface(typeFace);

注意a:打包了字体的程序会大很多,这也是没有办法的事。除非做成按需下载字体,这就依赖网络了;或者生成一个只包含所需汉字的字体文件。(2017年发布的Android Support Library v26增强了对字体的支持,见此视频。)
注意b:各字体可能会有自己的侧重点,比如支持生僻汉字的字体可能不支持emoji,支持emoji的字体可能不支持生僻汉字。
注意c:可以用SpannableString为一个字符串的部分字符使用指定的字体,见为部分字符指定字体在SpannableString使用指定字体

在按如上方法使用了开心宋体后,已经可以在Android 5.0.2模拟器上显示各区汉字:

在Android 5.0.2模拟器上默认字体的效果,可以看到CJK统一汉字扩展B、C、D、E区的汉字都无法显示:

附1,在Android 4.4.2模拟器上,使用开心宋体后,常用字反倒显示不出来了。
在4.3.1、4.4.2上,使用Simsun-ExtB字体也有类似情况,所以这应该是安卓4.x的问题。
难道是系统不支持多于65536个字符的字体?我没有去验证,仅仅是猜测。

附2,在Android 4.4.2模拟器上,使用默认字体的效果:

Android上显示生僻字的方法的更多相关文章

  1. 关于Unity程序在IOS和Android上显示内嵌网页的方式

    近期因为有须要在Unity程序执行在ios或android手机上显示内嵌网页.所以遍从网上搜集了一下相关的资料.整理例如以下: UnityWebCore 从搜索中先看到了这个.下载下来了以后发现这个的 ...

  2. JS文件中的中文在网页上显示为乱码解决方法

    转自:http://www.pc6.com/infoview/Article_63835.html 如果JS文件中的中文在网页上显示为乱码,不妨采用本文章中的方法来试一试,或许能解决使你很头疼的问题. ...

  3. HTML让文字在图片上显示的几种方法

    第一种方式是image 作为背景图片,即:background:url("......."); 第二种方式是将img块与文字块(文字块采用span标签显示)放在同一个div 中,然 ...

  4. 日期在苹果手机上显示NaN的处理方法

    注意两点即可: 1.苹果只认识 yyyy/mmmm/dddd/  这类格式的日期 2.如果输出后还要进行处理日期对比,苹果默认会带中文字,如:年月日,需要转成上面1当中的日期格式在转时间戳进行比较 G ...

  5. 在远程X server上显示图形的设置方法

    1.在服务器的/etc/ssh/sshd_config中,设置X11Forwarding yes,然后重启ssh服务,cd /etc/init.d这个目录下执行 ./ssh restart 2.在客户 ...

  6. unity,将camera设为don't clear在android上会显示不正常

    将camera设置为don't clear,在pc和ios上显示没问题,但在android上显示不正常,改为only depth可以.

  7. 教你用PS制作雨天窗户上透明水滴字

    雨天窗户上透明水滴字制作方法很简单,主要利用图层样式来实现.学习后可以让你对图层样式有更好的了解,认识. 先看下完成后的效果图: 步骤1: 在Photoshop中我们新建或Ctrl+N,创建1920x ...

  8. 利用SQLite在android上实现增删改查

    利用SQLite在android上实现增删改查 方法: 一.直接利用database.execSQL()方法输入完整sql语句进行操作 这种方法适用于复杂的sql语句,比如多表查询等等 这里适合于增删 ...

  9. Android上的MVP:如何组织显示层的内容

    MVP(Model View Presenter)模式是著名的MVC(Model View Controller)模式的一个演化版本,目前它在Android应用开发中越来越重要了,大家也都在讨论关于M ...

随机推荐

  1. 2018-2019-2 20175202实验一《Java开发环境的熟悉》实验报告

    2018-2019-2 20175202实验一<Java开发环境的熟悉>实验报告 一.实验内容 1.使用JDK编译.运行简单的Java程序: 2.使用IDEA 编辑.编译.运行.调试Jav ...

  2. Python 入门级报错处理

    问题1:Missing parentheses in call to 'print' 原因:因为Python2.X和Python3.X不兼容.我安装的是Python3.X,但是我试图运行的却是Pyth ...

  3. 18.22 sprintf函数功能

    函数功能:把格式化的数据写入某个字符串 函数原型:int sprintf( char *buffer, const char *format [, argument] … ); 返回值:字符串长度(s ...

  4. chrony配置的和相关命令

    ntp命令 查看时间同步源: $ chronyc sources -v 查看时间同步源状态: $ chronyc sourcestats -v 设置硬件时间 硬件时间默认为UTC: $ timedat ...

  5. Verilog编码规范与时序收敛

    Verilog编码规范与时序收敛 没有优先级的时候,尽量用case 时钟选择

  6. MPU9250九轴陀螺仪--读接口数据

    1.使用i2c链接到树莓派的scl , sda 接口vcc给3v引脚,gnd接树莓派gnd就ok. 2.要操作mpu必须使用mpu的寄存器实现对参数的设定以及读取,取官方下载资料看了一下,在githu ...

  7. MARK DOWN 书写格式说明

    MarkdownPad2 书写格式说明: Markdown是一种可以使用普通文本编辑器编写的标记语言,通过简单的标记语法,它可以使普通文本内容具有一定的格式,而MarkdownPad2是其中一种支持M ...

  8. java 通信

    UDP package com.le; import org.junit.Test; import java.io.IOException; import java.net.DatagramPacke ...

  9. nginx1.14.0版本server、location、rewrite配置

    server配置demo 在192.168.10.140(centos7)上修改: /home/program/nginx/conf/nginx.conf 添加一个server server { li ...

  10. java.util.concurrent包下集合类的特点与适用场景

    java.util.concurrent包,此包下的集合都不允许添加null元素 序号 接口 类 特性 适用场景 1 Queue.Collection ArrayBlockingQueue 有界.阻塞 ...