Android TextView设置textColor对♭、♯符号不生效问题求助

在Android开发过程中,修改TextView的textColor属性时,降号♭、升号♯两个符号的颜色不会随设置变更(其余特殊符号如ø可正常跟随textColor设置变色),在布局文件、代码中分别修改文字颜色均无法解决该问题。
复现代码
layout.xml布局代码
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="TextView" /> </androidx.constraintlayout.widget.ConstraintLayout>
业务实现代码
package com.example.stackoverflow; import android.app.Activity; import android.os.Bundle; import android.text.Html; import android.widget.TextView; public class activity extends Activity { TextView tv; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.layout); tv = findViewById(R.id.textView); tv.setText(Html.fromHtml("Normal text ♯ ♭, <sup><small>superscript ♯ ♭</small></sup><sub><small>subscript ♯ ♭</small></sub>")); tv.setTextColor(getResources().getColor(R.color.purple_200)) ; } }

问题原因
♯(U+266F,音乐升号)、♭(U+266D,音乐降号)属于Unicode中同时支持emoji渲染和普通文本渲染的字符,Android系统默认会优先调用内置彩色emoji字体渲染这两个字符,彩色emoji字形自带固定颜色,不会响应TextView的textColor属性。其余普通特殊符号(如ø)没有对应的emoji彩色字形,走常规文本字体渲染,因此可以正常跟随文字颜色变更。
解决方案
- 方案1:追加文本变体选择符,强制走普通文本渲染
改造成本最低,在每个♯、♭字符后追加Unicode变体选择符\uFE0E,强制系统将该字符识别为普通文本而非emoji,即可正常跟随textColor设置变色,不需要改动其他业务逻辑。
示例写法:tv.setText(Html.fromHtml("Normal text ♯\uFE0E ♭\uFE0E, <sup><small>superscript ♯\uFE0E ♭\uFE0E</small></sup><sub><small>subscript ♯\uFE0E ♭\uFE0E</small></sub>")); - 方案2:给富文本全范围设置前景色Span,覆盖emoji默认颜色
不需要修改原始字符串内容,在Html.fromHtml解析得到富文本对象后,给整个文本范围设置ForegroundColorSpan,直接覆盖emoji的默认彩色渲染:// 需提前导入android.text.SpannableString、android.text.style.ForegroundColorSpan、android.text.Spanned Spanned originSpan = Html.fromHtml("Normal text ♯ ♭, <sup><small>superscript ♯ ♭</small></sup><sub><small>subscript ♯ ♭</small></sub>"); SpannableString coloredSpan = new SpannableString(originSpan); int targetColor = getResources().getColor(R.color.purple_200); coloredSpan.setSpan(new ForegroundColorSpan(targetColor), 0, coloredSpan.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); tv.setText(coloredSpan); - 方案3:关闭TextView的emoji渲染能力
如果当前页面不需要展示任何emoji,可以直接关闭emoji渲染,所有字符都会走常规文本字体,自然响应textColor设置。使用AndroidX AppCompat 1.4.0及以上版本时,直接调用以下代码即可:
也可以通过给TextView设置不含emoji字形的自定义字体,绕开系统emoji字体的渲染逻辑。tv.setEmojiCompatEnabled(false);
内容的提问来源于stack exchange,提问作者Alberto
相关产品推荐
相关产品推荐

