QMUI Android 對外發布了一兩天了,收到了一些意見和建議,感覺比較突出的一個問題就是 Theme 的問題,今天就來聊聊這個話題。
起步
日常開發過程中,我們很少有機會去觸碰到 theme,也很少有文章提及到 theme, 更沒有依賴 theme 去開發 UI 元件的,QMUI 應該是除了 Android 官方元件外唯一的一個會依賴 theme 的開源庫吧,至少目前我沒發現有其它庫是這麼做的。我們這麼做的原因主要是讓 UI 元件可配置化,分為兩個方面:
- 不同的專案對顏色、間距、字型大小等的要求都不相同
- 同一個專案對同一個元件有統一化的配置,並且需要做到差異化
所以在引入 QMUI 時,一定要記得在 AndroidManifest
中更新
Application
或者 Activity
的 theme。
針對整個 Application:
<application
...
android:theme="@style/QMUI.Compat">
...
</application>複製程式碼
針對某個特定的 Activity:
<activity
android:name="..."
...
android:theme="@style/QMUI.Compat"/>複製程式碼
一般而言,我們都會在 theme.xml裡新增一個 AppTheme
來作為專案的 base
theme,Android Studio 建立專案 預設都會幫我們做好這一步,因此我們只需要更改 AppTheme
的 parent就行。
<style name="AppTheme" parent="QMUI.Compat">
<!-- 重寫系統 或者 QMUI 提供的 attr -->
</style>複製程式碼
關於 QMUI 和 QMUI.Compat
QMUI 提供了兩套 theme: QMUI 和 QMUI.Compat:
- QMUI 繼承自
android:Theme.Holo.Light
(4.x) 和android:Theme.Material.Light
(>=5.0),我們自己做了 Android L
前後 theme 的相容 - QMUI.Compat 繼承自 Theme.AppCompat.Light。這是系統做好了各個版本 theme 相容的處理
Android 官方是推薦用 AppCompat 系列, Android Studio 預設生成的 Activity
都是 AppCompatActivity
。此外, AppCompatActivity
、CoordinatorLayout
、TextInputLayout
等都必須在 AppCompat Theme 下執行,否則會 crash。因此大多數情況,你都應該使用 QMUI.Compat。只有當面對一些老專案,使用 QMUI.Compat 可能會造成較大影響時,才應該使用前一個 theme。
用 theme 進行配置的一個例子
這裡我用 QMUITabSegment
的配置來舉個例子, QMUITabSegment
是一個類似於 TabLayout
的元件,但比它有更豐富的效果,具體可以下載 QMUI Demo進行檢視。
先說一下QMUITabSegment
的配置項:
- 是否有 indicator:
qmui_tab_has_indicator
- indicator 高度:
qmui_tab_indicator_height
- indicator 是否在頂部:
qmui_tab_indicator_top
,為false則在底部 - item 的字型大小:
android:textSize
- item 的寬度是均分還是跟隨內容寬度:
qmui_tab_mode
- item 如果有icon,icon的位置在上下左右哪個位置:
qmui_tab_icon_position
一個自定義 view 的強大之處就是可以新增很多自定義屬性,但如果每次使用這個元件都要去重複寫一遍這些屬性,那會是很煩的,如何解決這種問題呢?有三種解決方案:
- 用一個類如
AppTabSegment
去繼承QMUITabSegment
,用 java 程式碼去 set 一遍這些屬性 - 抽取一個公用的 style,在使用處引用
- 利用 View 構造器的第三個引數,通過 theme 來配置,使用者感知不到配置的存在(QMUI 採用的方案)
第一種維護起來並不會優雅;第二種每次使用時都要去引入一遍 style,如果忘了 style 的名字, 還得去查;而在第三種配置下,使用者不需要做額外的事情,只需要一次配置即可,相當優雅。例如做如下配置:
<style name="AppTheme" parent="QMUI.Compat">
<item name="QMUITabSegmentStyle">@style/AppTabSegment</item>
</style>
<style name="AppTabSegment">
<item name="qmui_tab_has_indicator">false</item>
<item name="qmui_tab_indicator_height">1dp</item>
<item name="qmui_tab_indicator_top">false</item>
<item name="android:textSize">14sp</item>
<item name="qmui_tab_icon_position">left</item>
<item name="qmui_tab_mode">fixed</item>
</style>複製程式碼
這樣在使用的時候不加任何特殊的屬性就能獲得上述特效,有需要的話依然可以覆寫部分屬性,這對 QMUITabSegment
、QMUIPullRefreshLayout
這種整個 App 基本上只有一個樣式的元件是非常完美的配置方案。
QMUI 的所有自定義元件的屬性都在 qmui_attr.xml
, 其它 App 公用的值的定義都在qmui_attr_base.xml
。有需要的話可以去看看。
如何獲取 theme 中定義的屬性的值?
這個問題涉及android中 “@” 和 ”?“ 的區別:
- @: 如 @color、@string、@drawable,表示去取已經定義好的資源
- ?:只有 ?attr 的使用方式,表示去對應的 theme 中獲取相應的資源,不同的 actvitiy 可以有不同的 theme, 取出來的值也就可以不一樣
如果你想某一個 layout 佈局的作用 margin 等於 theme 中定義好的
qmui_content_spacing_horizontal
,那你可以這樣:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginLeft="?attr/qmui_content_spacing_horizontal"
android:layout_marginRight="?attr/qmui_content_spacing_horizontal">
<!-- children -->
</LinearLayout>複製程式碼
最後,歡迎大家試用,如果有任何意見或建議,歡迎留言或者在 Github 建立 issue。
本文全文轉載至:【QMUI教程】 Android Theme的使用 - 小松的技術部落格,已獲得轉載授權。