浅谈 Android 15 新 API:确保 TextView 完整展示、不被切断~

本文为稀土掘金技术社区首发签约文章,30天内禁止转载,30天后未获授权禁止转载,侵权必究!

前言

很多语言和文字拥有特殊的、复杂的写法、画法,一个字符可能延伸到前一个字符的区域,甚至后一个字符的区域。

如果文字的宽度没有做针对这种文字做额外的加宽处理,那么文字整体在边界区域会出现被切掉的现象。

比如如下的文字类型,最右边的文字 ร์ 的右上角的符号没有显示完全。

针对这个痛点,Android 15 进行了优化,如果 app 面向 Android 15 及更高的版本后,可以采用 setUseBoundsForWidth() 设置为 true,就可以拓宽 TextView 的显示区域。

可以看到,采用新设置之后,最右边的文字(ร์)的右上角的符号能完全显示了。

说明

宽度的调整会给已有的布局引起垂直方向上不对齐的可能性问题,所以该设置默认是关闭的。

另外,事实上光依赖 setUseBoundsForWidth() 还不够,还需要将 shiftDrawingOffsetForStartOverhang 设置为 true,那这个 API 干啥用的,我们在后面的实战环节会进行介绍。

除了 set 方法,Android 15 也提供了 getUseBoundsForWidth()getShiftDrawingOffsetForStartOverhang() 供开发者动态地调用。

当然,这两项设置在 XML 中也有相应的 attribute 支持,供开发者在布局中直接使用。

  • android:useBoundsForWidth bool
  • android:shiftDrawingOffsetForStartOverhang bool

实战

我们以 cursive 字体下的 Java 文字为例,进行该 API 的尝试。

xml 复制代码
    <TextView
        android:fontFamily="cursive"
        android:text="java" /> 

默认情况下没有效果,字符 J 的左下角被切掉了。

正如文档所说 Android 15 上 useBoundsForWidth 未指定的情况下,width 不会拓宽。

xml 复制代码
<TextView
     android:fontFamily="cursive"
     android:text="java"
     android:useBoundsForWidth="true" /> 


仍然没有效果,因为还要依赖 shiftDrawingOffsetForStartOverhang 属性。

xml 复制代码
<TextView
     android:fontFamily="cursive"
     android:text="java"
     android:useBoundsForWidth="true"
     android:shiftDrawingOffsetForStartOverhang="true"/> 

可以看到有效果了,J 字符的左边展示完全了。

Inspecting 检查

让我们 dump 角度 double confirm 下 View 的尺寸上是否有变化。

最简单快速的是使用 LayoutInspector。

通过 inspecting,咱们发现视觉上明明拓宽了的 TextView 在 inspector 里展示的 width 却都是 60dp。

Dumpsys 确认

暂时不确定这是 Inpector 的 bug 还是确实如此,我们尝试用 adb dump 下宽高。

bash 复制代码
    adb shell dumpsys activity top

我们用 adb dump 一下试试。

bash 复制代码
      ACTIVITY com.ellison.osvdemo/.textView.TextViewWidthActivity d53efc9 pid=6004 userId=0 uid=10196 displayId=0(type=INTERNAL)
        ...
        View Hierarchy:
          com.android.internal.policy.DecorView{2c56827 V.E...... R....... 0,0-1080,2400 aid=0}[]
            android.widget.LinearLayout{8f36ad4 V.E...... ........ 0,0-1080,2400}
              android.view.ViewStub{e29447d G.E...... ......I. 0,0-0,0 #10201cb android:id/action_mode_bar_stub}
              android.widget.FrameLayout{1e6f72 V.E...... ........ 0,63-1080,2337}
                androidx.appcompat.widget.ActionBarOverlayLayout{7165fc3 V.E...... ........ 0,0-1080,2274 #7f080092 app:id/decor_content_parent}
                  androidx.appcompat.widget.ContentFrameLayout{9866040 V.E...... ........ 0,147-1080,2274 #1020002 android:id/content}
                      ...
                      com.google.android.material.textview.MaterialTextView{df946ed V.ED..... ........ 461,394-619,539 #7f0801fa app:id/textview4}
                      com.google.android.material.textview.MaterialTextView{fbebfb3 V.ED..... ........ 449,933-631,1078 #7f0801fb app:id/textview5}
                      com.google.android.material.textview.MaterialTextView{db064e9 V.ED..... ........ 449,1472-631,1617 #7f0801fc app:id/textview6}

可以看到几个 TextView 在左上右下的坐标:

  • 默认情况下的 Java 文字 TextView 的坐标: 461, 394 ~ 619, 539,宽度是 619 - 461 = 158px
  • 仅开启 setUseBoundsForWidth 情况下的 Java 文字 TextView 的坐标: 449, 933 ~ 631, 1078,宽度是 631 - 449 = 182px
  • 外加开启 shiftDrawingOffsetForStartOverhang 情况下的 Java 文字 TextView 的坐标: 449, 1472 ~ 631, 1617,宽度也是 631 - 449 = 182px

至此,大家应该能得到结论:

  • setUseBoundsForWidth 实际已经拓宽了宽度,但没有减少文字在 TextView 内部的 padding,导致仍被切掉、显示不全
  • shiftDrawingOffsetForStartOverhang 并没有控制宽度,则是在 draw 的时候向右 offset,促使文字不被切掉

我们将效果截图放大,大家仔细看下:

细致对比之后,可以看出,两者宽度实际上一致,唯一不同的是后者将内容往右进行了平移。

结语

几乎每年的 Android 系统升级,Google 都会针对 TextView 基础组件进行改动或新的支持。

今年的 Android 15 版本也是一样,针对 TextView 进行了 3 处修改:

  1. 避免文本切断的 setUseBoundsForWidth API 和 shiftDrawingOffsetForStartOverhang API
  2. 依据 locale 选择适合的 TextView 行高数值的 setLocalePreferredLineHeightForMinimumUsed API
  3. 设置的字体测量最小值的 setMinimumFontMetrics API
  4. 针对 TextView 内容换行的专用属性 <nobreak> API

本文阐述了第 1 点,后续将逐步阐述其他几个变化,敬请期待。

DEMO

AndroidOSVDemo

参考

相关推荐
拭心10 小时前
Google 提供的 Android 端上大模型组件:MediaPipe LLM 介绍
android
带电的小王13 小时前
WhisperKit: Android 端测试 Whisper -- Android手机(Qualcomm GPU)部署音频大模型
android·智能手机·whisper·qualcomm
梦想平凡13 小时前
PHP 微信棋牌开发全解析:高级教程
android·数据库·oracle
元争栈道13 小时前
webview和H5来实现的android短视频(短剧)音视频播放依赖控件
android·音视频
阿甘知识库14 小时前
宝塔面板跨服务器数据同步教程:双机备份零停机
android·运维·服务器·备份·同步·宝塔面板·建站
元争栈道15 小时前
webview+H5来实现的android短视频(短剧)音视频播放依赖控件资源
android·音视频
MuYe15 小时前
Android Hook - 动态加载so库
android
居居飒16 小时前
Android学习(四)-Kotlin编程语言-for循环
android·学习·kotlin
Henry_He18 小时前
桌面列表小部件不能点击的问题分析
android
工程师老罗19 小时前
Android笔试面试题AI答之Android基础(1)
android