Android 之夜間模式(多主題)的實現思路

XycZero發表於2015-08-12

引言

夜間模式其實屬於多主題切換的一種,不過是最麻煩的一種。因為在夜間模式下不僅要切換主色調,次要色調等等,還要覆蓋一些特殊的顏色,因為在夜間模式下總不能什麼都是黑的把,那不得醜死-。-,所以當你夜間模式完成後,你的App對於日後多主題的擴充套件就可以輕鬆勝任了。

實現思路

多數App由於歷史原因當對其進行夜間模式的功能改造時,工作量是比較大的,所以在真正開始著手實現前,我們還是應該先明確夜間模式(多主題)到底有多少實現的思路以及它們的優劣,這樣才可以有效的避免專案延期的情況出現。

  1. 自定義attr屬性。

    這是最基礎的方法,就是通過自定義attr屬性,在不同的theme中進行不同的實現,然後在layout和style中呼叫。這種方法改程式碼改動量比較大,而且根據不同的主題,drawable(5.0以上不用),selector等xml檔案必須要相應的定義多份,因為 android由於相容性和自身的原因並不能在這些檔案中識別attr屬性(會報type解析錯誤),當然style和theme可以直接識別使用。

    在shape,selector中不識別attr屬性我個人覺得可能是android的bug,因為5.0以上的drawable中是可以識別attr屬性的,所以理論上是可行的。若能解決在selector等xml中的識別問題,該方法就能大大減少重複程式碼了。

  2. 重寫getResource方法

    這是第三方微部落格戶端Fuubo所採用的方式。重新Acticity和Application的getResource方法,統一同一顏色的是呼叫名字,對於不同主題在getRsource中進行判斷並返回對應的顏色值。

    這樣做的好處是你不用定義很多份的drawable,selector之類的xml檔案,你的所有顏色都將在getRsource中通過R.color中判斷並替換,省去很多工作,而且基本可以不改動你以前的程式碼。

    當然壞處也是顯而易見的,當你的App複雜時所有的替換邏輯都集中在getRsource()中將會顯得十分的臃腫,並且你無法使用theme中的系統屬性,因為theme中的屬性並不是通過Activity的getResource()進行載入的,所以例如系統的popMenu就無法改變其背景色等屬性,都需要你自定義實現了。

切換方式

談到夜間模式或多主題切換,就不得不說另一個問題主題的切換方式。

  1. 重啟Activity。

    這是最常用的切換方式,也是最暴力的解決方式,哈哈。

    當然需要注意的是一定要在 super.onCreate(savedInstanceState);之前呼叫,不然會發生很多的意外問題-,- 。

    至於重啟的方式有很多,可以直接Intent.FLAG_ACTIVITY_CLEAR_TOP,再啟動一個新的 Activity。或者finish自己再重新startActivity,或者最簡單的直接呼叫onRecreate()即可(相當於發生了 configuration change),然後再加上一個過渡的動畫效果,這就根據自己App的情況自行選擇了。

  2. 重新整理所有控制元件。

    其實現的思路是在自定義屬性的基礎上,再自定義每個控制元件,並將與主題顏色相關的屬性全部封裝在控制元件中,然後通過一個統一的介面,每當主題發生改變時,對當前Activity從根View開始進行遞迴遍歷重新整理,而對於listview則是清空RecycleBin中的所有child view,這樣就等於是強行重新整理了整個listview。

    這種方式最大的優點就是可以不重啟Activity就可以更換Activity的主題顏色,大大優化了使用者的體驗。當然缺點也很明顯,因為如果你的App不是一開始就這麼做,那麼改造的工作量更加巨大(因為還要實現自定義屬性=。=)。

    目前github已有人實現了這種思路的換主題框架, 傳送門

換膚

上面並沒有討論換主題的另一個方向:換膚。因為個人覺得簡單換膚其實與換主題色的區別並不是特別大,只需要新增換膚apk的下載,並將其資源載入到app中替換即可,網上有很多的實現思路,再這就不在傫述。而對於複雜的換膚,即如天天動聽一樣不僅可以更換主題顏色,資原始檔,還可以更換 Layout佈局!這。。。增加的工作量就不是多一點點的問題了(和以上討論的情況相比),所以暫不討論-。-。

結語

以上是關於Android切換主題的一點心得,希望對您有些許幫助,有不正確的地方歡迎指出討論,如果您有其他的一些實現思路,也歡迎補充,謝謝。

相關文章