【QMUI教程】 Android Theme的使用

Kayo發表於2017-09-01

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。此外, AppCompatActivityCoordinatorLayoutTextInputLayout等都必須在 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>複製程式碼

這樣在使用的時候不加任何特殊的屬性就能獲得上述特效,有需要的話依然可以覆寫部分屬性,這對 QMUITabSegmentQMUIPullRefreshLayout 這種整個 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的使用 - 小松的技術部落格,已獲得轉載授權。

相關文章