Android 本地化適配:RTL(right-to-left) 適配清單
- 2019 年 10 月 3 日
- 筆記
本文首發自公眾號:承香墨影(ID:cxmyDev),歡迎關注。
一. 序
越來越多的公司 App,都開始淘金海外,尋找更多的機會。然而海外市場千差萬別,無論是市場還是用戶的使用習慣,都有諸多的不同。
當你接觸一款出海 App 的時候,除了需要了解海外 Google Service 的整個生態圈,還要做好不同語言的適配。語言適配最通用的做法就是根據不同系統語言設定,配置不同的語言資源(strings.xml),而其中比較特殊的就是例如阿拉伯的 RTL 布局,它不僅改變了語言,還改變了 UI 布局和使用習慣。
我們常用的習慣,稱之為 LTR(Left-To-Right),其意為我們的閱讀和書寫習慣,是從左向右延伸的。而 RTL(Right-To-Left) 則正好相反,它的閱讀和使用的習慣都是從右向左,常見使用 RTL 習慣的語言有阿拉伯語、希伯來語等。
今天就來聊聊,一個成熟的 Android App,想要做 RTL 適配,需要關注什麼,想要適配 RTL 有哪些任務清單。
如果你維護的 App 有國際化的要求,那這個問題是遲早需要面對的。
二. Android 支持 RTL
2.1 什麼是 RTL?
正如前面介紹的,RTL 是 Right-to-left 的縮寫,其意為閱讀和書寫的習慣,是從右向左延伸的。再對比一下我國人自身的使用習慣,都是 LTR 的,也就是從左向右。
RTL 可以簡單理解是 LTR 的鏡像,當需要適配 RTL 的時候,除了翻譯語言本身,還需要做到的就是 UI 布局,從中軸上鏡像反轉。
雖然 RTL 不符合我們國人的使用習慣,但是全球範圍內依然有一部分人保持着 RTL 的習慣,比較常見的就是阿拉伯語、希伯來語等。
就 Android 系統來說,Android 4.1 開始就在 TextView 和 EditView 中增加了對雙向文本的優先支持,允許其文本內容從左向右(LTR)到從右向左(RTL)的顯示和切換。而在 Android 4.2 開始,增加了對 RTL 鏡像布局完全原生的支持。
也就是在 Android 4.2(Api Level 17)及之後,在 UI 上的布局鏡像,是原生支持的。在這些系統版本上,只要用戶系統語言切換到「RTL 系語言」,首先系統 UI 會直接左右鏡像切換,此時如果你的 App 支持 RTL 鏡像布局時,也會自動切換布局方向。
2.2 App 如何支持 RTL 鏡像
正如前面介紹的一樣,LTR 到 RTL 的切換,不是由開發者控制的,而通常是由系統語言來控制的。
當系統語言切換為「RTL 系語言」時,還需要你的 App 支持 RTL 鏡像布局。
這裡所謂的支持,其實只需要配置一個屬性即可,就是 AndroidManifest.xml 配置文件中的一個清單元素。需要在 <applictaion>
標籤下,配置元素 android:supportsRtl="true"
。
此時當系統語言切換的時候,你的 App 也會跟着切換 UI 布局為鏡像後的效果。
除了需要開啟 supportsRtl
屬性之外,還需要一些布局屬性的配合。
簡單來說,就是將布局需要的所有 xxxLeft/xxxRight "替換"為 xxxStart/xxxEnd。
例如我們常用的 Padding 和 Margin,都有類似 paddingLeft 和 layout_marginRight 屬性,這些就需要"替換"成 paddingStart 和 layout_marginEnd 屬性。當然不止於此,還有一些 gravity、drawableLeft 等屬性需要"替換"。原則上,所有 Left/Right
都需要變換為 Start/End
就好了。
這些屬性,官方文檔中已經幫我們列舉出來了。
到這裡應該了解了,Android App 支持 RTL 鏡像的主要流程,就兩步:
- App 增加
android:supports="true"
屬性。 - 調整 UI 布局屬性,從
left/right
到start/end
切換。
那麼問題來了,我們在日常編碼的過程中,應該使用 left/right 還是 start/end?還是兩者都需要?
注意到我前面提到的 UI 布局屬性的替換時,是打了引號的,你是否需要使用 start/end
來完全替換 left/right
,完全取決於 App 當前的 minSdkVersion 值。
正如前面所提到的,Android 對 RTL 的原生支持,是在 Android 4.2 中才具備的,也就是說,如果 App 的 minSdkVersion 大於等於 4.2,你只需要使用 start/end
屬性,但如果還需要支持 4.2 以下的設備用戶,那就需要保留 left/right
和 start/end
兩者。
在低於 4.2 的系統中,不識別 supportsRtl
和 start/end
屬性,所以不會造成影響。但是需要注意,在適配完成之後,後續開發新頁面時的編碼習慣。
2.3 AS 助力調整布局屬性
如果當前需要適配的是一個成熟項目,並且其中的布局習慣還是使用 left/right
系的屬性,那麼針對所有頁面布局文件,進行手工調整就是一個非常大的工作量了。
所幸的是 AS 提供了自動化的支持。
你可以在 Refactor → Add RTL Support Where Possible 來開啟 RTL 的自動調整。
它會自動將項目中所有的 left/right
屬性都替換為 start/end
屬性,如果想要適配 Android 4.2 以下的設備,需要保留兩者,那麼在 Run 之前,勾選 Relpace Left/Right Properties with Start/End Properties 選項即可。
早期的 AS 自動支持 RTL 布局的時候,效率會有一些問題,轉換的時候如果布局過多,可能會卡死,但是新版的 AS 已經優化了很多,轉換效率上還是可以接受的。
另外這畢竟是自動替換,在替換完成之後,還是需要每個頁面都測試一遍,看看效果才算完,有時候還需要我們做一些微調的工作。例如 AS 自動替換 RTL 布局的時候,如果使用了 include
標籤,其中用到的方向屬性不會被替換。
自動化雖然方便了我們機械的重複,但也必須介入人工的干預符合預期。
三. RTL 細節調整
要做這種全全局的改動,必然會有一些細節需要微調的,這裡簡單寫一些 RTL 布局中會需要使用到的細節調整技巧。
3.1 利用全局樣式,批量修改屬性
在適配 RTL 的過程中,無法避免的就是有一些屬性必須要設置。例如 EditView 就需要設置以下屬性。
android:textAlignment="viewStart" android:gravity="start" android:textDirection="locale"
那我們就可以將這些屬性在 style.xml 中全局為 EditText 設置上。
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar"> ... <item name="editTextStyle">@style/EditTextStyle.Alignment</item> ... </style> <style name="EditTextStyle.Alignment" parent="@android:style/Widget.EditText"> <item name="android:textAlignment">viewStart</item> <item name="android:gravity">start</item> <item name="android:textDirection">locale</item> </style>
同時 TextView 也需要設置 android:textDirection
屬性,也可以採用相同的方法用 Style 的方式全局設置。
3.2 針對 RTL 的資源適配
除了布局上的適配之外,還有一些資源的適配,資源適配主要說兩塊內容:Drawable(mipmap) 以及 Layout 布局資源。
先來說說 Drawable 的適配。例如在不同方向的布局下,使用不同的圖標。
上圖就是個很典型的例子,在調整布局到 RTL 時,還需要注意返回「←」的圖標也需要替換成「→」。
這裡依然使用 Android 對資源使用的限定符的方式,可以創建 drawable-ldrtl
目錄,將翻轉後的圖標,放在這個目錄下。如果需要限定 dpi,可以在目錄名後面追加。
res/ drawable/ a.png drawable-ldrtl/ a.png // 對標 drawable/a.png 的 RTL 圖標 drawable-xhdpi/ b.png drawable-ldrtl-xhdpi/ b.png // 對標 drawable-xhdpi/b.png 的 RTL 圖標
接下來再說說 Layout 布局的 RTL 布局效果適配。有些特殊的頁面,可能光鏡像化還不夠,還需要針對性的做一些 UI 上的調整,那最簡單的做法就是做兩套布局,互不影響。
既然 Drawable 可以通過資源限定符的方式,設置 RTL 布局下使用的圖標,其實布局也可以。
對於布局文件,可以在目錄下追加限定符 layout-ldrtl/
,如果想對某個語言做布局適配,也可以增加語言限定,例如阿拉伯語可以用 layout-ar/
。
res/ layout/ main.xml // 默認布局 layout-ar/ main.xml // 阿拉伯語布局 layout-ldrtl/ main.xml // RTL 布局
針對 RTL 的 UI 布局規範,Material Design 下有一個規範的文檔(https://material.io/design/usability/bidirectionality.html#localization),設計師可以參考。
3.3 代碼判斷是否 RTL?
有些控件的屬性,是通過代碼動態調整的,那在使用的過程中,就需要在代碼中,判斷當前的環境,是 RTL 還是 LTF,才可以確定後續的屬性設置。
通過獲取 Configuration 的 locale 來判斷當前的環境,為了兼容,在 TextUtilsCompat 下也提供了類似的方法。
public boolean isRtl() { return TextUtilsCompat.getLayoutDirectionFromLocale( getContext().getResources().getConfiguration().locale) == ViewCompat.LAYOUT_DIRECTION_RTL; }
isRtl()
方法可以直接拿來使用,依此判斷結果,執行後續的操作。
3.4 不是所有控件都支持 RTL
雖說從 Android 4.2 開始,原生支持 RTL 方向布局,但是也有一些控件是不支持的,例如 ViewPager,就不支持 RTL 的方向。
這其實沒有什麼很好的辦法,要麼和產品商量對此處的容忍,要麼找一些其他的解決方案。
針對 ViewPager 的 RTL 化,在 Github 就有對應的開源庫 RtlViewPager(https://github.com/diego-gomez-olvera/RtlViewPager) 可供使用。其原理也是將數據進行倒序重排,沒什麼好說的,源碼不多,有興趣可以自己看看。
四. 適配 RTL 要如何估期?
再來聊聊適配 RTL 時,估算開發周期的問題。
除了 App 本身在設計研發之初,就是為了中東的土豪設計的之外,多數情況下,我們都是因為各種外部原因,需要在一款成熟的 App 上,適配 RTL 鏡像布局。例如市場驗證有大量「RTL 系語言」的付費用戶,或者產品經理認為存在「RTL 系語言」的潛在用戶。
什麼時候適配 RTL,完全是由外部因素決定的。但是當需要適配的時候,我們作為開發者,最直觀要面對的現實問題就是,適配 RTL 需要做哪些事?這個任務需要多少時間能夠完成?需要哪些人來配合,哪些任務是可以並行的?
要精確估計 App 的 RTL 化,很難,因為工作量主要來自適配,說到適配,工作量就可大可小了。App 大量使用第三方控件的就比只使用原生控件的工作量大;產品經理和設計師,允許部分頁面適配有差異的,也會比高要求還原的工作量大。
這些在適配完成之前,誰也不知道效果如何,既然沒有什麼好的方法,那就試一試吧,只需要三步,你可以拿着一個明確的鏡面翻轉效果,來估計適配的難度。
- 設置
android:supportsRtl="true"
,讓 App 支持 RTL。 - AS 自動轉換布局屬性,支持 RTL 布局效果。
- 打開開發者選項中的「強制使用從右到左的布局方向」,強制 RTL 布局。
此時你基本上可以看到一個 80% RTL 化的 App,剩下的就是把頁面都檢查一遍,看看有沒有用到哪些控件不支持 RTL,哪些 Drawable 需要替換、哪些布局需要微調。然後針對性的調整即可。
有一些控件不支持 RTL 就會比較麻煩,有源碼的就改改源碼,沒源碼的就看有沒有地方可以 Hook 解決。
總之需要做什麼,清單是固定的。有了明確的任務,自然就容易估計開發周期了。
列舉一下適配 RTL 的任務清單:
- App 支持 RTL,AS 自動轉換布局屬性支持 RTL,從開發者選項里強制 RTL 布局方向。
- 按頁面排查,檢查出需要翻轉的 Drawable 資源,打包交給設計師,反轉後替換。
- 檢查布局翻轉後的效果,和設計師確定需要適配翻轉後的 UI 效果。
- 找到不支持 RTL 化的控件,可以從源碼的角度分析,能改源碼的改源碼,不能改源碼的嘗試 Hook 解決或找替代方案。
- 翻譯 RTL 系語言資源 strings.xml,放入對應的資源目錄,例如阿拉伯語需要放入 /values-ar/strings.xml 目錄,將系統語言切換到阿拉伯語,排查所有頁面文字與控件的匹配度。
- 整體驗收,微調效果。
其中需要和產品、設計、翻譯配合的,都可以提前準備,讓任務並行化。當然在適配的過程中,還有一些實際的問題,就需要遇到問題再解決問題了。
五. 小結時刻
本文聊了如何在一個成熟的 App 上,適配 RTL 鏡像效果,以及如何快速的適配。最後還列出了一個適配時,需要調整關注的清單列表,希望對你有所幫助。
本文就到這裡,如果有所幫助,留言、轉發、點好看是最大的支持,謝謝!
reference:
https://material.io/design/usability/bidirectionality.html#localization
https://android-developers.googleblog.com/2013/03/native-rtl-support-in-android-42.html
https://developer.android.com/training/basics/supporting-devices/languages?hl=zh-cn
公眾號後台回復成長『成長』,將會得到精心準備的學習資料。