移動應用的開發中,有時我們會需要例如更換皮膚此類的功能,andorid采用xml配置UI的方式,這個問題或許還容易解決些,iOS的主要UI邏輯則是在代碼中控制的,如果沒有一個強大的框架方案,這個問題將變得非常棘手。網上也有很多諸如此類功能的優秀案例與框架,在這篇博客中,我與大家分享下我的解決方案,其中如果有不恰或者糟糕之處,希望與高人一起交流。
首先我的設計思路是采用通知的方式,原理可以如下理解為以下幾步:
1、在系統的通知中心注冊一個通知
2、所有需要更改皮膚功能的controller作為這個通知的監聽者
3、設計一個皮膚的model類
4、將controller中有關皮膚設置的屬性從model中取
5、在切換皮膚前更改皮膚model
6、發送更改皮膚的通知
上面的6個步驟是這整個框架的基本邏輯,框架無非是將這些邏輯進行優化與封裝。下面這張圖很爛,但是思路很清晰:
首先最上面是我設計的一個切換主題的manager,我這裡的設計有個缺陷,我將manager和主題配置相關的model混合在了一起,寫的時候簡單了些,可這給框架的邏輯上帶來了混亂,所以我在圖中使用曲線和虛橢圓將其分離,manager來控制切換model的屬性,我們在controller中取model的屬性進行配置,這個manager的邏輯位置是交互時間與通知中心的橋梁。manager中的核心代碼如下:
//單例方法 +(instancetype)sharedTheSingletion{ static YHTopicColorManager * sharedModel = nil; static dispatch_once_t predicate; dispatch_once(&predicate, ^{ sharedModel = [[YHTopicColorManager alloc] init]; }); return sharedModel; } //這個方法應該分離在model中,從本地讀取當前的主題模式,更改後我們只需要更改本地數據 然後重新調用這個方法即可 -(void)getTopicModel{ //從本地讀取 int tp = [YHSASystemSettingManager sharedTheSingletion].topic; if (tp==0) { //默認為白天主題 tp=dayTime; [YHSASystemSettingManager sharedTheSingletion].topic = tp; } switch (tp) { //這裡是我定義的一些枚舉,拿白天和夜間模式示范 case dayTime://白天模式 { //這裡面定義一些白天模式下 控件的顏色屬性 也可以定義其他 _navColor=[UIColor colorWithRed:10/255.0 green:85/255.0 blue:160/255.0 alpha:1]; _bgColor=[UIColor colorWithRed:1 green:1 blue:1 alpha:1]; _btnColor=[UIColor colorWithRed:10/255.0 green:85/255.0 blue:160/255.0 alpha:1]; _textColor=[UIColor colorWithRed:0 green:0 blue:0 alpha:1]; _btnTextColor=[UIColor colorWithRed:1 green:1 blue:1 alpha:1]; _navTextColor= [UIColor whiteColor]; } break; case nightTime://夜間模式 { //這裡面定義夜間模式下的相關控件的顏色屬性 _navColor=[UIColor colorWithRed:10/255.0 green:85/255.0 blue:160/255.0 alpha:1]; _bgColor=[UIColor colorWithRed:0 green:0 blue:0 alpha:1]; _btnColor=[UIColor colorWithRed:10/255.0 green:85/255.0 blue:160/255.0 alpha:1]; _textColor=[UIColor colorWithRed:1 green:1 blue:1 alpha:1]; _btnTextColor=[UIColor colorWithRed:1 green:1 blue:1 alpha:1]; _navTextColor= [UIColor whiteColor]; } break; default: break; } } //發送更改主題的消息 +(void)postTopicChangeMessage{ [[NSNotificationCenter defaultCenter]postNotificationName:YHTopicChangeTopicNotication object:nil]; }
在manager調用通知中心發送通知後,我們要讓所有需要改變主題的視圖控制器都接收到通知,最簡便的做法是,我們設計一個父類,讓父類監聽通知,所有需要有主題更改功能的控制器繼承於它即可,這個father controller的核心代碼如下:
//移除監聽 -(void)dealloc{ [[NSNotificationCenter defaultCenter]removeObserver:self]; } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. //添加監聽主題更換的通知 [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(useYHTopicToCreatViewWithModel) name:YHTopicChangeTopicNotication object:nil]; //協議中的方法,加載主題 一會再說 [self useYHTopicToCreatViewWithModel]; } //子類實現如下方法 -(void)useYHTopicToCreatViewWithModel{ }
到目前,我們已經可以順利接收到主題切換的通知,可是要所有子類都步伐一致的執行相同一個操作,我們可以通過一個協議來約定,這就是圖中的主框架的protocol,這個協議中規定一個特定的方法,我們在父類中調用,子類中實現,當收到通知時,所有子類都將重新加載這個方法,如果我們將皮膚設置部分在這個方法中實現,那麼正是我們想要的效果,所有皮膚設置都被重新加載了。協議如下:
/** *這裡定義主題的風格 */ typedef enum { dayTime=1,//白天 nightTime//夜間 }YHTopicModel; @protocol YHTopicProcotol //所有可以更換主題的界面必須遵守這個協議調用並實現如下方法 //將視圖中控件的顏色攝住部分全部放在這個方法中 @required -(void)useYHTopicToCreatViewWithModel; @end
這時,就剩下我們這套邏輯的最後一步了,我們只需要將控件的顏色設置寫在子類的協議方法中,並且,這些設置的數據來源於model這個模型,整個體系就完成了,子類實現方法如下:
-(void)useYHTopicToCreatViewWithModel{ //獲取到模型 YHTopicColorManager * model = [YHTopicColorManager sharedTheSingletion]; //加載模型數據 [model getTopicModel]; //進行設置 self.view.backgroundColor = model.bgColor; _schoolLabel.textColor = model.textColor; _phoneLabel.textColor = model.textColor; _secertLabel.textColor = model.textColor; _reWriteSecretLabel.textColor = model.textColor; _questionLabel.textColor = model.textColor; _answerLabel.textColor = model.textColor; _registBtn.backgroundColor = model.btnColor; [_registBtn setTitleColor:model.btnTextColor forState:UIControlStateNormal]; }
我簡單寫了一些界面,不論任何地方切換皮膚,所有界面效果都會改變:
切換夜間模式前:
開啟夜間模式後:
自己的思路實現更換主題的一種方法,真誠的想與志同道合的朋友交流開發經驗,如果你想批評,點撥,交流或者是借鑒我的代碼,Q316045346隨時歡迎。
來自:http://my.oschina.net/u/2340880/blog/495670