Hi,你們好,我是承香墨影!php
Android 8.0 已經發布了有一陣子了,若是你有在關注它,你應該會知道它新增了一個對於 TextView 字體大小變更的新特性:Autosizing。html
自己這個新特性,若是隻是在 Android 8.0 纔有效,對於開發者而言,就顯得有點雞肋了,可能還須要一段時間才能普及使用。不過呢,在 Android Support v26 之上,也對 Autosizing 提供了兼容支持,最低能夠支持到 Android Level 14。android
這樣,咱們就有了研究的必要了,接下來本文就來說解一下,Autosizing 屬性,你在使用過程當中的全部細節。算法
Autosizing 容許 TextView 根據其內部文本的顯示大小,動態的調整其 TextSize 屬性值得大小,經過此設置,開發者能夠很輕鬆的在具備動態內容的狀況下,對不一樣的屏幕中,文本大小進行優化。c#
簡單來講,一個 100dp 長度的 TextView ,正常來講只能顯示 10 個 10dp 的文字,而若是它的內容超出了 10 個字,之前的通用作法,是經過屬性設置,讓它在末尾顯示 "…" 。而採用了 Autosizing 這個新特性,它的方案是將字體的尺寸縮小,例如縮小到 8dp,讓 TextView 能夠容納下更多的文字,顯示徹底。而這一切,使用 Autosizing 咱們只須要設置一些屬性就能夠作到,很是的簡單。設計模式
上面這個 Gif 應該能夠很直觀的描述 Autosizing 的特性,而它也反映出,觸發 Autosizing 從新計算 TextSize 的時機有兩個:數組
Autosizing 的核心設計思想,就是爲了讓 文本 儘量的徹底顯示在既定大小的 TextView 中,哪怕是修改它的文字大小。app
前面也提到,使用 Autosizing 實際上是區分使用 Android Api Level 26(8.0) 和 使用 Support Library v26 兩種。它們的使用方式,會略微有點區別。ide
下面,咱們先來了解一下它們之間的區別。工具
Autosizing 的帶來的效果很簡單,就是根據文字的內容,動態修改 TextSize ,而想要使用它,能夠經過動態編碼和靜態的 layout-xml 佈局屬性的方式使用。
對於 Android 8.0 Api:
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 上並無對應的方法能讓咱們調用,因此咱們須要繞一層。
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 的方式進行講解。
到這裏,你應該對 Autosizing 有了基本的概念,知道它是幹什麼的。
那麼,若是讓你來設計一個這樣的功能,你會想要作到哪些點?
嗯,功能上大概就是這些了,已經知足個人須要了。
若是你看了 Autosizing 的文檔,你會發現,它所有都支持!
Autosizing TextView Doc:
https://developer.android.google.cn/guide/topics/ui/look-and-feel/autosizing-textview.html
Autosizing 是直接做用在 TextView 上的,對於它的開啓和關閉,咱們能夠直接操做 autoSizeTextType 屬性。
對於動態編碼,可使用 TextViewCompat 的 setAutoSizeTextTypeWithDefaults()
方法,下面是它的方法簽名。
參數中的 textView
是咱們要操做的 TextView,而 autoSizeTextType
,就是咱們關心的 Autosizing 的開關屬性了,它接受兩個參數。
咱們也能夠經過 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,含義和上面代碼中設置的參數一致。
粒度的含義其實就是 Autosizing 每次變更的最小單位,固然在設置粒度的同時,你還須要爲其設置一個縮放的範圍,最大值和最小值。
這樣,在 Autosizing 生效的時候,它會在這個範圍內,按照咱們設定的粒度,去動態的調整文字的大小。
想要操做這些屬性,動態編碼的方式你須要調用 TextViewCompat 的 setAutoSizeTextTypeUniformWithConfiguration()
方法。
參數很直觀,沒什麼好解釋的,一個最小值、一個最大值、變更的粒度、前面設置的尺寸的單位。
咱們能夠經過 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 會認爲這是一個無效的設置,將它忽略掉。
若是你按上一小節,介紹的屬性,設置了 Autosizing 的粒度,就能夠在這個範圍內,根據咱們設置的粒度進行縮放。一般,使用粒度來控制基本上能夠達到咱們的要求,可是若是對縮放有更精準的要求,例如:[10.15,40,60,100] 這樣的縮放,使用粒度就達不到咱們的要求了。
針對這樣的操做,Autosizing 也提供了對應的屬性來設置,那就是 預設尺寸(Preset Size)。
若是想要使用預設尺寸,動態編碼的方式,你須要操做 TextViewCompat 的 setAutosizeTextTypeUniformWithPresetSizes()
方法。
預設尺寸能夠接受一個尺寸數組,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>
複製代碼
預設尺寸很是簡單,這裏就再也不給運行效果了。
到這裏,咱們就把 Autosizing 的基本使用細節,都講解清楚了。可是,依然還有一些概念,是在文檔上沒有反應出來的,下面咱們就來說講這些 「經驗」。
若是你想要使用 Autosizing,就必須對 TextView 這個控件,限定大小,不能使用 wrap_content
來做爲限定符。
用官方文檔話來講,使用 wrap_content
可能出現不可預料的效果。其實這也很是好理解,若是 TextView 的尺寸不是固定的,那就不存在 TextView 從新計算尺寸的依據了,同比放大 TextView 就能夠達到容納文字的效果了。
我在實際使用過程當中會發現,它會阻止放大效果。例如一個 TextView 中使用了 Autosizing,一直增長文本內容,是能夠正常縮小的,可是當你刪除文本的時候,它並不會隨之放大文字尺寸。
可是不肯定還有沒有其它的問題,這裏建議按照官方文檔的建議來操做,限定 TextView 的尺寸。
雖然一般做用在 TextView 上的新屬性,對於一樣用於顯示文本的控件,例如:Button、EditText 等,都是一樣適用的。
可是 Autosizing 就是這麼特殊,它只對單純只能顯示 文本 的控件有效,例如 Button,而對於 EditText 這種能夠輸入 文本 的控件,是無效的。
這個,你能夠在 AppCompatTextViewAutoSizeHelper 這個類的 supportsAutoSizeText()
方法中找到答案,它是一個兼容類,用於向下兼容 Autosizing 特性。
這裏能夠看到,只要不是 AppCompatEditText 就返回 true,註釋也說明了這一點。
暫時沒有想到這樣設計的緣由,多是由於輸入文本的控件,自己長度就是在常常變化的,是一個極端不可控的狀況,因此應該爲輸入的控件,限定一個固定的尺寸。
若是想要控制文字的縮放尺寸爲限定的範圍內,例如使用 粒度 限定它在一個 10sp 的精度下縮放;或者使用預設尺寸,限定一些尺寸,讓它只能使用咱們預約的一些尺寸。
可是這些,並非必定的。
例如,咱們使用預設尺寸,預設了一組[10sp,20sp,25sp,40sp],這樣一組尺寸,其中,可能某個尺寸就永遠不會被命中,例如 25sp。
這是由於,Autosizing 在起做用的時候,會去計算尺寸是否合適,假如到 20sp 以後,再減小文字,這個時候先獲取 25sp ,經過計算髮現 25sp 也放不下這些文字,就會直接跳到 40sp 這個尺寸上去。
因此,並非咱們設定的尺寸,它就是以線性的方式去獲取尺寸。
若是你想在 TextView 中,只顯示一行文字,在以前你可使用 android:singleLine
這個屬性,對其標記。而若是你 同事使用 Autosizing,你會發現 Autosizing 就再也不生效,它會在末尾顯示 「…」。
所幸的是,android:singleLine
已經被標記爲廢棄,因此自己咱們就不建議使用它,若是你想讓 TextView 只顯示單行文字,可使用 android:maxLines="1"
屬性,它是能夠正常和 Autosizing 兼容的。
Autosizing 提及來很是的簡單,可是它能有哪些適用場景呢?簡單說說我能想到的一些適用場景吧,你們能夠開放思惟。
這個,其實很常見,例如一些選擇題的 UI,當你有多個須要選擇答案的 UI ,並列的顯示出來。若是它們的文字長度是可變的(一般都是可變的),你除了放大某一行的高度以外,如今還可使用 Autosizing 來控制它的大小。
例如最近比較火的衝頂大會類 App,就是一個標準的選擇題的 UI 佈局。
咱們能夠在答案文字過多的時候,使用 Autosizing 將它縮小,就能正好放在這個既定大小的選項 UI 中。
Autosizing 在 App 的多語言適配中,也能夠大放異彩。
首先你要考慮到,當你想讓 App 適配多語言的話,一個很嚴重的問題,就是不一樣的語言,描述同一個詞的時候,長度是不一致的。
例如中文下簡單的一句:我是 Android 開發者,翻譯成不一樣的語言,長度是不一致的。
在這樣的狀況下,咱們若是有 Autosizing 就很是的好解決這個問題了。
本文到這裏,就已經完成了 Autosizing 的全部細節,從基本使用到注意事項,應該算是解釋的很詳細了。
不知道你以爲 Autosizing 在實際使用中,還有什麼使用場景?能夠在評論中留言,分享給你們!
今天在承香墨影公衆號的後臺,回覆『成長』。我會送你一些我整理的學習資料,包含:Android反編譯、算法、設計模式、虛擬機、Linux、Kotlin、Python、爬蟲、Web項目源碼。
我另外還維護了一個技術交流羣,有興趣能夠在公衆號後臺回覆:"加羣"
推薦閱讀: