iOS控制器之基類設計


題記

在進入新公司后。經過這一個月的重構項目,終於把項目做到了個人相對滿意的程度(還有一種不滿意的叫老板的需求,提過多次意見也沒用= =!)。在這次重構中按照以前的思路設計出了個人覺得比較適用的一個基類。在這里筆者會把此基類基本的設計說明一遍。

基類設計需求

1.在我們搭建框架之初一般會設計一個ViewController基類,並在基類ViewDidLoad中設置一個隨機的背景顏色。並通過touch手勢來進行界面的跳轉,以此來設計最開始的一個界面跳轉框架,並通過界面顏色的變幻來驗證我們界面跳轉是否有做到正常跳轉。
2.接下來可能需要設計到的一個問題就是導航欄返回按鈕的問題,因為系統自帶的導航欄返回按鈕相對來說不太好看。通常我們會將返回按鈕進行自定義。在這里我們通過方法直接實現重定義導航欄左邊按鈕達到我們想要的效果
3.在很多時候我們對View子視圖進行布局時,可能子視圖的范圍偶爾會超時View視圖bounds范圍。此時可能還需要設計一個方法來讓View的子視圖即使在View的bounds范圍之外也能得以呈現。

Vc基類設計實現

對於上述需求,其中需求1最好解決。我們普遍的做法是寫一個自己的工具類,然后在viewDidLoad中通過工具類生成一個隨機的顏色作為基類視圖的背景色,從而查看是否達到跳轉目的。

self.view.backgroundColor = [BQTools randomColor];

接下來是自定義返回按鈕的問題,(目前大部分APP都是用導航欄推出下個控制器,如果用present模態推出。那可忽略此段內容)。基於最方便的實現方法即在VIew視圖加載時,直接給導航欄生成一個左側欄item。並實現其點擊方法達到導航欄pop的目的。此處的“back”為自定義的返回按鈕視圖

UIBarButtonItem * leftBarItem = [[UIBarButtonItem alloc] initWithImage:[[UIImage imageNamed:@"back"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] style:UIBarButtonItemStylePlain target:self action:@selector(leftBarItemAction:)];
self.navigationItem.leftBarButtonItem = leftBarItem;

這樣的情況是方便的解決的需求2問題,但衍生出一個新問題,即當導航欄的第一控制器也會存在一個左側欄item,並實現了pop方法。所以我們需要在這里再加上一個判定情況,使其在導航欄第一控制器不存在此item。所以更新后的代碼如下

if ([self.navigationController.viewControllers indexOfObject:self] != 0) {
    UIBarButtonItem * leftBarItem = [[UIBarButtonItem alloc] initWithImage:[[UIImage imageNamed:@"back"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal] style:UIBarButtonItemStylePlain target:self action:@selector(leftBarItemAction:)];
    self.navigationItem.leftBarButtonItem = leftBarItem;
}

最后是View子視圖的布局問題,很多時候我們都會有超出視圖范圍以外的子視圖存在,此時就需要在View視圖上布局一個scrollview來達到視圖滾動查看View視圖bounds子視圖的目的。既然存在這種情況,那我們在這里就可以仿照cell的情況 直接給一個contentView(為ScrollView)來做為子視圖容器。最后再通過方法遍歷直接獲取子視圖的frame通過比較修改contentView的展示區域,此時所有的子視圖應該添加到contenView之上

//生成contentView
self.automaticallyAdjustsScrollViewInsets = NO;
self.automaticallyAdjustsScrollViewInsets = NO;
self.contentView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 64, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - 64)];
[self.view addSubview:self.contentView];
self.contentView.contentSize = self.contentView.bounds.size;

//在viewWillAppear中去判斷修改contentView的展示范圍
CGFloat contentHeight = 0;
NSArray * subViews = self.contentView.subviews;
for (UIView * view in subViews) {
    if (CGRectGetMaxY(view.frame) > contentHeight) {
        contentHeight = CGRectGetMaxY(view.frame);
    }
}
//筆者項目主要是上下滾動,如視圖可能超出視圖右側,也能以同樣方式實現其效果
if (contentHeight > self.contentView.bounds.size.height) {
   self.contentView.contentSize = CGSizeMake(self.contentView.bounds.size.width, contentHeight);
}

注意

有部分控制器可能會存在導航欄背景色透明的情況,此時若導航欄透明contentView的布局就需要從0,0處開始,所以還需要給出方法對contentView的frame進行調整。關於導航欄的背景色調整筆者使用的是第三方的導航欄

使用范圍、場景

以上基類只是一個最基本常用的原型,可能在實際項目中還需要拓展一些其他的共通屬性,比如主題色,導航欄隱藏,標簽欄出現隱藏等情況,所以在項目中使用時,還需要根絕自己的實際需求進行修改。另外作為第三種需求來說,布局直接超出View視圖bounds范圍的話一般是因為UI切圖時給出的圖高度較長。所以在筆者的項目中使用等比例適配(並非寬高比,而是純基於寬度的對比比例在進行設計)來搭配此基類,效果較好(因為筆者進行完全等比例適配,所以圖片同樣會有縮放情況,在此種情況下如不是用重繪,可能會存在效率上的浪費)。但如果是使用masonry進行布局,可能就不太需要按照筆者的基類進行設計了。

后記

對於控制器基類的設計,個人有個人的理解。筆者在這里拋出自己的設計思路及部分代碼封裝,希望各位能指點交流。如上述有何錯誤之處,請指正。謝謝!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM