Android低版本SDK中Unicode字符显示问题咨询
在低版本Android SDK中显示Unicode Emoji的解决方案
嘿,这个问题我维护旧版本Android应用的时候真的踩过坑!确实,高版本里用Html.fromHtml()能轻松显示的Emoji,到了低版本设备上就直接“失踪”,除了图片替代,其实还有几个更优雅的办法,给你详细说说:
1. 用官方EmojiCompat库(最推荐)
Google专门推出了这个库解决旧设备Emoji显示问题,省心还靠谱,支持API 19+:
- 第一步:添加依赖
在你的app模块build.gradle里加:implementation "androidx.emoji:emoji:1.2.0" // 如果需要支持更低版本,可以搭配emoji-appcompat依赖 - 第二步:初始化库
在Application的onCreate()里初始化:@Override public void onCreate() { super.onCreate(); // 使用内置的Emoji字体包,也可以用下载式配置减少APK体积 EmojiCompat.Config config = new BundledEmojiCompatConfig(this); EmojiCompat.init(config); } - 第三步:使用Emoji
要么直接在布局里用EmojiTextView替代普通TextView:
要么给普通TextView处理文本:<androidx.emoji.widget.EmojiTextView android:id="@+id/emoji_text" android:layout_width="wrap_content" android:layout_height="wrap_content"/>
这个库会自动把系统不支持的Emoji替换成内置的渲染图形,完全不用自己操心字体的事!EmojiCompat.get().registerInitCallback(new EmojiCompat.InitCallback() { @Override public void onInitialized() { String emojiText = "\uD83C\uDFCC Golf \uD83C\uDFCC"; textView.setText(EmojiCompat.get().process(emojiText)); } });
2. 打包支持Emoji的自定义字体
如果你的APP需要支持API 19以下的极旧设备,这个方法兼容性拉满:
- 选字体:找包含完整Emoji字形的字体,比如Noto Emoji、Google Sans Emoji,下载对应的
.ttf或.otf文件 - 放资源:把字体文件放到
src/main/assets/fonts目录下 - 代码加载:
缺点是会增加APK体积(大概3-5MB),但胜在兼容性极强。// 加载字体 Typeface emojiFont = Typeface.createFromAsset(getAssets(), "fonts/NotoEmoji-Regular.ttf"); // 给TextView设置字体(如果全是Emoji的话) textView.setTypeface(emojiFont); // 如果要混合普通文本和Emoji,用Spannable单独给Emoji部分设置字体 SpannableString spannable = new SpannableString("\uD83C\uDFCC Golf \uD83C\uDFCC"); spannable.setSpan(new TypefaceSpan(emojiFont), 0, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); spannable.setSpan(new TypefaceSpan(emojiFont), 7, 9, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); textView.setText(spannable);
3. 用HtmlCompat替代原生Html.fromHtml
低版本Android的原生Html.fromHtml()对Unicode转义的支持很差,换成AndroidX的HtmlCompat会好很多:
String htmlText = "\uD83C\uDFCC Golf \uD83C\uDFCC"; textView.setText(HtmlCompat.fromHtml(htmlText, HtmlCompat.FROM_HTML_MODE_LEGACY));
不过这个方法还是依赖系统字体支持,如果系统本身没有Emoji字形,还是得配合上面的字体方案才行。
最后说说图片替代
如果以上方法都没法覆盖你的目标设备(比如API 10以下),那图片替代确实是最后的选择,但可以优化一下:用SpannableString把Emoji替换成ImageSpan,不用每个地方都写ImageView,稍微减少点繁琐度:
SpannableString spannable = new SpannableString("⛳ Golf ⛳"); // 替换第一个⛳ Drawable emojiDrawable = getResources().getDrawable(R.drawable.ic_emoji_golf); emojiDrawable.setBounds(0, 0, emojiDrawable.getIntrinsicWidth(), emojiDrawable.getIntrinsicHeight()); ImageSpan imageSpan = new ImageSpan(emojiDrawable); spannable.setSpan(imageSpan, 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); // 替换第二个⛳,重复操作 spannable.setSpan(imageSpan, 7, 8, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); textView.setText(spannable);
总结一下:优先用EmojiCompat,省心又官方;需要极低版本兼容就用自定义字体;图片替代是实在没办法的选择。
内容的提问来源于stack exchange,提问作者AlienBuster




