天天看點

iOS開發之主題皮膚

大概的步驟如下:

(1):整個應用依賴于一個主題管理器,主題管理器根據目前的主題配置,加載不同主題檔案夾下的主題

(2):在應用的各個Controller中,涉及到需要更換主題圖檔或顔色的地方,由原來的寫死方式改為從主題管理器擷取(此處可以看到,雖然.xib配置UI會比編碼渲染UI效率來得高,但在靈活性以及協同開發方面還是有些弱了)

(3):在主題設定Controller中,一旦切換主題,則需要像系統的通知中心發送消息(這一步的目的,主要是為了讓那些已經存在的并且UI已建構完成的對象修改他們的主題)

最終的效果圖見:

https://github.com/yanghua/iBus#version-102preview

首先來看看主題檔案夾的目錄結構:

iOS開發之主題皮膚

可以看到,通常情況下主題都是預先做好的,當然了,這裡因為我沒有後端server,如果你的應用是擁有後端server的,那麼可以做得更加強大,比如不将主題檔案存儲在Bundle中,而是存儲在應用sandBox的Document中。這樣你在應用啟動的時候就可以check

server

是否有新的主題包,如果有就download下來,釋放到Document,這樣會友善許多,而不需要在更新之後才能夠使用新主題。扯遠了,這裡可以看到這些檔案夾是藍顔色的,而非黃顔色,可見它不是xcode

project的Group,它們都是真實存儲的檔案夾(它們也是app的bundle的一部分,隻是擷取的方式有些不同罷了,這樣做的目的就是為了友善組織各個主題的檔案、目錄結構)。

看看擷取主題檔案夾路徑的方式:

ThemeManager:

可以看到,ThemeManager對外開放了三個屬性以及兩個執行個體方法,并且ThemeManager被建構為是單例的(Single)

在執行個體初始化的時候,同時執行個體化主題的相關配置:

initCurrentTheme定義:

這裡從sqlite中擷取了主題類型、主題顔色,然後配置了主題屬性,同時初始化了一緻的UINavigationBar。

在其他Controller中,擷取圖檔的方式不再是:

取而代之的是:

來確定img.png是來自目前主題檔案夾下的img.png

實作如下:

到主題設定界面,選擇一個新主題,會調用changeTheme方法:

這是一個簡單的ThemeManager,通常有可能會有更多的配置,比如: themedFontWithName:(NSString

*)fontName 等,當然方式都是一樣的。

上面這些都隻是定義,看看它是怎麼運轉的,怎麼跟Controller組合的。

BaseController中:

注:BaseController是所有其他Controller的super

class,任何時候,你去寫一個應用程式也好,一個app也罷,你一開始總是應該規劃好類型的繼承關系,這是非常重要的,就個人經驗而言,我總是會在建立一個應用程式之後,就立即建構一個super

class,這會為你省去很多麻煩事。又廢話了,進入正題。

在BaseController中,我們開放一個public method:

該類預設沒有實作,主要用于供sub class去 override。

比如其中一個子controller的實作如下:

可以看到,所有需要使用主題的UI控件的相關設定,都抽取出來放到了configUIAppearance中。

該方法,在所有子controller中都不會顯式調用,因為在BaseController的viewDidLoad方法中以及調用了。這樣,如果子類override了它,就會調用子類的,如果沒有override,則調用BaseController的預設實作。

可以看到,上面的方法中配置了一些UI的外觀,在一個view show出來的時候會被調用,還有一個調用點當然是主題改變的時候!

主題改變的時候,所有應用的controller無非是兩種狀态:

(1)未被執行個體化

(2)已經被執行個體化,而且view已經建構完成并且可見

對于第一種狀态,我們不需要太多的擔心,因為根據選擇新主題的時候,會調用ThemeManager的changeTheme方法,該方法會update資料庫的主題配置,同時init并config新的主題,是以未被執行個體化的controller在後面被執行個體化的時候,肯定會應用新的主題。

但對于已經可見的主題就不是第一種情況那樣了,除非你重新show他們,否則是不會主動應用新的主題的,但将其他controller都distory之後再重新建構,根本不可能。是以,這裡應用了ios的Notification,并再次展示了需要一個BaseController的好處,因為我們不需要為已存在的每一個controller注冊消息通知并實作處理收到通知的方法,我們在BaseController中做,就等于在所有繼承它的sub

controller中做了,不是嗎?

那麼我們首先要在BaseController中像Notification

center注冊我們關注的Notification_For_ThemeChanged

Notification:(在BaseController的ViewDidLoad中調用該注冊方法)

同時給出消息處理的邏輯:

}

可以看到這裡又調用了configUIAppearance,由于繼承關系,這裡的self指針指向的并非BaseController執行個體(而是sub

controller的執行個體),是以調用的也是sub

controller的方法。是以,雖然可能還停留在“主題設定的界面”,但其他已存活的controller已經接受到了切換主題的Notification,并悄悄完成了切換。

最後再看看切換主題的大緻邏輯:

大緻的流程就是這樣~

如果你覺得代碼片段過于零散,沒有關系,所有的實作代碼都放到了github上。

原文釋出時間為:2013-07-28

本文作者:vinoYang