文字太多?控件过小?试试 TextView 的新特性 Autosizing 吧!

Hi,你们好,我是承香墨影!html

Android 8.0 已经发布了有一阵子了,若是你有在关注它,你应该会知道它新增了一个对于 TextView 字体大小变更的新特性:Autosizingandroid

自己这个新特性,若是只是在 Android 8.0 才有效,对于开发者而言,就显得有点鸡肋了,可能还须要一段时间才能普及使用。不过呢,在 Android Support v26 之上,也对 Autosizing 提供了兼容支持,最低能够支持到 Android Level 14。算法

这样,咱们就有了研究的必要了,接下来本文就来说解一下,Autosizing 属性,你在使用过程当中的全部细节。c#

1、什么是 Autosizing?

Autosizing 容许 TextView 根据其内部文本的显示大小,动态的调整其 TextSize 属性值得大小,经过此设置,开发者能够很轻松的在具备动态内容的状况下,对不一样的屏幕中,文本大小进行优化。设计模式

简单来讲,一个 100dp 长度的 TextView ,正常来讲只能显示 10 个 10dp 的文字,而若是它的内容超出了 10 个字,之前的通用作法,是经过属性设置,让它在末尾显示 "…" 。而采用了 Autosizing 这个新特性,它的方案是将字体的尺寸缩小,例如缩小到 8dp,让 TextView 能够容纳下更多的文字,显示彻底。而这一切,使用 Autosizing 咱们只须要设置一些属性就能够作到,很是的简单。数组

上面这个 Gif 应该能够很直观的描述 Autosizing 的特性,而它也反映出,触发 Autosizing 从新计算 TextSize 的时机有两个:app

  1. TextView 中的文字增多到没法容纳的地步。
  2. TextView 自己的尺寸被放大或缩小了。

Autosizing 的核心设计思想,就是为了让 文本 尽量的彻底显示在既定大小的 TextView 中,哪怕是修改它的文字大小。ide

2、使用 Autosizing

2.1 Autosizing 不一样使用方式

前面也提到,使用 Autosizing 实际上是区分使用 Android Api Level 26(8.0) 和 使用 Support Library v26 两种。它们的使用方式,会略微有点区别。工具

下面,咱们先来了解一下它们之间的区别。布局

Autosizing 的带来的效果很简单,就是根据文字的内容,动态修改 TextSize ,而想要使用它,能够经过动态编码和静态的 layout-xml 布局属性的方式使用。

对于 Android 8.0 Api:

  1. 动态编码是直接操做的 TextView 上的方法。
  2. layout-xml 布局属性,是使用的 android: 命名空间下的属性进行设置。
<?xml version="1.0" encoding="utf-8"?>
<TextView
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:autoSizeTextType="uniform" />

而在低于 Android 8.0 的设备上,只能使用 Support v26 了。此时,TextView 上并无对应的方法能让咱们调用,因此咱们须要绕一层。

  1. 动态编码,使用 TextViewCompat 中提供的方法。
  2. layout-xml 布局属性,须要使用 app: 命名空间下的属性,记住要添加 xmlns:app="http://schemas.android.com/apk/res-auto" 这个命名空间。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

  <TextView
      android:layout_width="match_parent"
      android:layout_height="200dp"
      app:autoSizeTextType="uniform" />
</LinearLayout>

使用标准的 8.0 Api 的使用场景,在现阶段会很是的少,因此咱们这里只是简单了解一下区别就行了,下面的文章内容会主要以 Support v26 的方式进行讲解。

2.2 Autosizing 基础

到这里,你应该对 Autosizing 有了基本的概念,知道它是干什么的。

那么,若是让你来设计一个这样的功能,你会想要作到哪些点?

  1. 有开关限制,只在咱们须要的 TextView 上,才开启这个特性。
  2. 容许设置边界值,最大缩放和最小缩放。
  3. 能配置每次缩放的最小尺寸,例如:10sp 为粒度进行缩放。
  4. 能预设一些缩放的定位尺寸,例如预设一组尺寸,只让它在这个范围内的值中选一个。
  5. 方便的 Api ,能够经过 layout-xml 属性和动态编码的方式操做它。

嗯,功能上大概就是这些了,已经知足个人须要了。

若是你看了 Autosizing 的文档,你会发现,它所有都支持!

Autosizing TextView Doc:

https://developer.android.goo...

2.3 Autosizing 开关

Autosizing 是直接做用在 TextView 上的,对于它的开启和关闭,咱们能够直接操做 autoSizeTextType 属性。

对于动态编码,可使用 TextViewCompat 的 setAutoSizeTextTypeWithDefaults() 方法,下面是它的方法签名。

setAutoSizeType

参数中的 textView 是咱们要操做的 TextView,而 autoSizeTextType,就是咱们关心的 Autosizing 的开关属性了,它接受两个参数。

  • AUTO_SIZE_TEXT_TYPE_NONE:关闭自动调整功能。
  • AUTO_SIZE_TEXT_TYPE_UNIFORM:开启统一缩放碎片轴和垂直轴。

咱们也能够经过 layout-xml 属性的方式,来设置 autoSizeTextType,由于是 Support ,因此使用的 app: 命名空间下的属性。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

  <TextView
      android:layout_width="match_parent"
      android:layout_height="200dp"
      app:autoSizeTextType="uniform" />

</LinearLayout>

app:autoSizeTextType 一样接收两个参数 uniform 和 none,含义和上面代码中设置的参数一致。

2.4 操做 Autosizing 的粒度

粒度的含义其实就是 Autosizing 每次变更的最小单位,固然在设置粒度的同时,你还须要为其设置一个缩放的范围,最大值和最小值。

这样,在 Autosizing 生效的时候,它会在这个范围内,按照咱们设定的粒度,去动态的调整文字的大小。

想要操做这些属性,动态编码的方式你须要调用 TextViewCompat 的 setAutoSizeTextTypeUniformWithConfiguration() 方法。

setConfiguration

参数很直观,没什么好解释的,一个最小值、一个最大值、变更的粒度、前面设置的尺寸的单位。

咱们能够经过 unit 参数,经过 TypedValue 来设置前面设置的几个参数的单位,例如:sp 、dp、px,均可以。

这里操做的参数,在 layout-xml 中,都提供了对应的属性可供咱们使用。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

  <TextView
      android:layout_width="match_parent"
      android:layout_height="200dp"
      app:autoSizeTextType="uniform"
      app:autoSizeMinTextSize="12sp"
      app:autoSizeMaxTextSize="100sp"
      app:autoSizeStepGranularity="2sp" />

</LinearLayout>

下面咱们举两个例子看看,就清晰了。

在默认状况下,若是你没有设置这三个属性,Autosizing 会根据当前 TextView 控件的大小,估算出一个最大值和最小值,而且将粒度设置为 1sp 。

能够看到,它设置的尺寸是跳动的,很是的不可控,咱们很难知道下一次缩放,会将 文本 尺寸,设置成多大,因此才须要使用 粒度 的概念来限制它缩放的大小。

例如,如今咱们修改上面的例子,将(minSize,maxSize),限制在 (10sp,80sp)之间,粒度(Granularity)设置为 10sp,此时再来看它的效果。

到这里能够看到,它每次放大或者缩小,粒度都是以 10sp 为基准。

因此,若是你须要使用 Autosizing ,强烈建议你使用 粒度 来控制它缩放的大小,让它在可控的范围内使用。须要注意的是,这里介绍的三个属性,必定要设置在一个合理的范围内,不然 TextView 会认为这是一个无效的设置,将它忽略掉。

2.5 预设尺寸范围

若是你按上一小节,介绍的属性,设置了 Autosizing 的粒度,就能够在这个范围内,根据咱们设置的粒度进行缩放。一般,使用粒度来控制基本上能够达到咱们的要求,可是若是对缩放有更精准的要求,例如:[10.15,40,60,100] 这样的缩放,使用粒度就达不到咱们的要求了。

针对这样的操做,Autosizing 也提供了对应的属性来设置,那就是 预设尺寸(Preset Size)。

若是想要使用预设尺寸,动态编码的方式,你须要操做 TextViewCompat 的 setAutoSizeTextTypeUniformWithPresetSizes() 方法。

preset_size_method

预设尺寸能够接受一个尺寸数组,Autosizing 就会从咱们设定的尺寸数组中,取一个尺寸进行设置。同时你能够为这些尺寸设置一个统一的尺寸单位。

若是想要在 layout-xml 使用属性的形式使用预设尺寸,你首先须要一个 array 的资源,而后经过 autoSizePresetSizes 属性进行设置便可。

array 资源的格式:

<resources>
  <array name="autosize_text_sizes">
    <item>10sp</item>
    <item>12sp</item>
    <item>20sp</item>
    <item>40sp</item>
    <item>100sp</item>
  </array>
</resources>

定义好 array 的尺寸资源以后,就能够在 layout-xml 中使用它。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

  <TextView
      android:layout_width="match_parent"
      android:layout_height="200dp"
      app:autoSizeTextType="uniform"
      app:autoSizePresetSizes="@array/autosize_text_sizes" />
</LinearLayout>

预设尺寸很是简单,这里就再也不给运行效果了。

3、查缺补漏

到这里,咱们就把 Autosizing 的基本使用细节,都讲解清楚了。可是,依然还有一些概念,是在文档上没有反应出来的,下面咱们就来说讲这些 “经验”。

3.1 TextView 必须限定尺寸

若是你想要使用 Autosizing,就必须对 TextView 这个控件,限定大小,不能使用 wrap_content 来做为限定符。

用官方文档话来讲,使用 wrap_content 可能出现不可预料的效果。其实这也很是好理解,若是 TextView 的尺寸不是固定的,那就不存在 TextView 从新计算尺寸的依据了,同比放大 TextView 就能够达到容纳文字的效果了。

我在实际使用过程当中会发现,它会阻止放大效果。例如一个 TextView 中使用了 Autosizing,一直增长文本内容,是能够正常缩小的,可是当你删除文本的时候,它并不会随之放大文字尺寸。

可是不肯定还有没有其它的问题,这里建议按照官方文档的建议来操做,限定 TextView 的尺寸。

3.2 Autosizing 不能做用在 EditText 中

虽然一般做用在 TextView 上的新属性,对于一样用于显示文本的控件,例如:Button、EditText 等,都是一样适用的。

可是 Autosizing 就是这么特殊,它只对单纯只能显示 文本 的控件有效,例如 Button,而对于 EditText 这种能够输入 文本 的控件,是无效的。

这个,你能够在 AppCompatTextViewAutoSizeHelper 这个类的 supportsAutoSizeText() 方法中找到答案,它是一个兼容类,用于向下兼容 Autosizing 特性。

not_support_edittext

这里能够看到,只要不是 AppCompatEditText 就返回 true,注释也说明了这一点。

暂时没有想到这样设计的缘由,多是由于输入文本的控件,自己长度就是在常常变化的,是一个极端不可控的状况,因此应该为输入的控件,限定一个固定的尺寸。

3.3 预设尺寸不必定都命中

若是想要控制文字的缩放尺寸为限定的范围内,例如使用 粒度 限定它在一个 10sp 的精度下缩放;或者使用预设尺寸,限定一些尺寸,让它只能使用咱们预约的一些尺寸。

可是这些,并非必定的。

例如,咱们使用预设尺寸,预设了一组[10sp,20sp,25sp,40sp],这样一组尺寸,其中,可能某个尺寸就永远不会被命中,例如 25sp。

这是由于,Autosizing 在起做用的时候,会去计算尺寸是否合适,假如到 20sp 以后,再减小文字,这个时候先获取 25sp ,经过计算发现 25sp 也放不下这些文字,就会直接跳到 40sp 这个尺寸上去。

因此,并非咱们设定的尺寸,它就是以线性的方式去获取尺寸。

3.4 和 singleLine 冲突

若是你想在 TextView 中,只显示一行文字,在以前你可使用 android:singleLine 这个属性,对其标记。而若是你 同事使用 Autosizing,你会发现 Autosizing 就再也不生效,它会在末尾显示 “…”。

所幸的是,android:singleLine 已经被标记为废弃,因此自己咱们就不建议使用它,若是你想让 TextView 只显示单行文字,可使用 android:maxLines="1" 属性,它是能够正常和 Autosizing 兼容的。

4、使用场景

Autosizing 提及来很是的简单,可是它能有哪些适用场景呢?简单说说我能想到的一些适用场景吧,你们能够开放思惟。

4.1 限定条目的 UI

这个,其实很常见,例如一些选择题的 UI,当你有多个须要选择答案的 UI ,并列的显示出来。若是它们的文字长度是可变的(一般都是可变的),你除了放大某一行的高度以外,如今还可使用 Autosizing 来控制它的大小。

例如最近比较火的冲顶大会类 App,就是一个标准的选择题的 UI 布局。

cddh

咱们能够在答案文字过多的时候,使用 Autosizeing 将它缩小,就能正好放在这个既定大小的选项 UI 中。

4.2 多语言

Autosizing 在 App 的多语言适配中,也能够大放异彩。

首先你要考虑到,当你想让 App 适配多语言的话,一个很严重的问题,就是不一样的语言,描述同一个词的时候,长度是不一致的。

例如中文下简单的一句:我是 Android 开发者,翻译成不一样的语言,长度是不一致的。

  • 英语:I am an Android developer
  • 阿拉伯语:أنا مطور الروبوت
  • 意大利语:Sono uno sviluppatore Android
  • 德语:Ich bin ein Android-Entwickler
  • 法语:Je suis un développeur Android

在这样的状况下,咱们若是有 Autosizing 就很是的好解决这个问题了。

5、小结

本文到这里,就已经完成了 Autosizing 的全部细节,从基本使用到注意事项,应该算是解释的很详细了。

不知道你以为 Autosizing 在实际使用中,还有什么使用场景?能够在评论中留言,分享给你们!

今天在 承香墨影公众号的后台,回复『 成长』。我会送你一些我整理的学习资料,包含:Android反编译、算法、设计模式、虚拟机、Linux、Kotlin、Python、爬虫、Web项目源码。

我另外还维护了一个技术交流群,有兴趣能够在公众号后台回复:"加群"

推荐阅读:

相关文章
相关标签/搜索