万丈红尘千杯酒,
千秋霸业一壶茶。
React Native 的 Text 在 Android 部分手机上单行渲染会出现“明明渲染空间足够,但是却出了省略号”的现象, 通过一通源码阅读和操作, 发现原因是这样的:
React Native 不是简单的去将 Text 设置给 TextView,然后通过 TextView 去 measure 获取 View 的大小, 而是自己实例化一个 Paint 去测量 Text,测量得到大小后,设置给 TextView。
那么不一致就产生了, TextView 主动 measure 和 实例化一个 paint 去 measure 得到的大小并不一致。
原因是某些手机(例如小米10、MIUI12)的 paint 在没有设置 typeface 时,它默认使用的 typeface 竟然不是系统指定的默认字体(这实属于魔改官方系统不全面,出漏洞了)
这就导致某些手机上 React Native 测量的大小小于 TextView 上实际能够展现全部 Text 的大小,因而出现了省略号。
所以我们我们魔改下 RN 源码:
//ReactTextShadowNode.java
private Layout measureSpannedText(Spannable text, float width, YogaMeasureMode widthMode) {
if(!isTypefaceSet){
// 从 TextView 里获取 typeface 以使得测量准确
isTypefaceSet = true;
TextView tv = new TextView(getThemedContext());
sTextPaintInstance.setTypeface(tv.getTypeface());
}
// 原本的代码
}
这样我们就能使得测量一致了。这也告诉我们:
当我们想用 Paint 绘制文本的时,我们也需要这样从 TextView 里获取默认 Typeface,否则就会被像素眼设计师怼了,最后 app 里从 TextView 里读取出 typeface,然后存储起来,公用。
吐槽:RN 这种完全自己搞 measure,完全不走官方逻辑,搞得问题一堆一堆的。
在使用 Function Component 来写 RN bundle 时,踩到了一个坑:
如果首次加载的是这个 bundle,那么样式就会丢失。最终发现实遗漏了 EStyleSheet.build() 方法调用,导致样式对象为空了。而在使用 Class Component 时,会把这个方法写在基类,而业务人员使用时也不会被遗漏。 而我们采用将 EStyleSheet.build() 放在一个通用的 hook 上来最大程度避免遗漏。