1. 程式人生 > >獻給初學iOS的小盆友們------微博app專案開發之一專案初始化

獻給初學iOS的小盆友們------微博app專案開發之一專案初始化

獻給初學iOS的小盆友們——微博app專案開發之一 專案初始化

本人自學iOS也有七八個月了,不敢說學到很深入了,但也算入了門。此次微博app專案參考了傳智播客培訓教材,主要學習內容有架構思想,封裝思想,程式碼重構,業務邏輯等內容,專案涵蓋面廣泛,講解易懂,且採用純程式碼方式搭建UI,希望對那些沒有時間看視訊的初學者們有所幫助。相信學習完本套專案,初學者會在程式設計思想上有一個很大的提升。

內容

  • 專案素材獲取
  • 環境配置
  • 自定義tabBarController
  • 修改tabBar內部結構
  • 劃分結構

本節資料

1.1 專案素材獲取

首先模仿一個專案,需要圖片等素材,單憑自己是做不出來的。本專案提供了基本的圖片素材供下載使用,一般專案素材的獲取步驟如下:

  • 開啟蘋果電腦iTunes應用,選擇頂部欄“AppStore”項
  • 然後在搜尋框內輸入“微博”並搜尋
  • 找到微博並點選,進去後點選微博圖示下的“取得”按鈕
  • 輸入 iCloud賬戶密碼後即可下載
  • 左上角下載按鈕可以顯示下載進度
  • 點選頂部欄“我的iPhone應用按鈕”
  • 找到微博應用,右鍵點選,選擇“在Finder中顯示”
  • 可以看到下載的是ipa型別的檔案,使用解壓檔案解壓後即可得到微博應用資料夾
  • 進入資料夾後,選擇Payload下的Weibo.app檔案,右鍵點選後選擇“顯示包內容”,即可看到微博應用所需的所有圖片,以後專案模仿都會用得到

1.2 環境配置

開發任何一個大型的應用都需要提前對開發環境進行配置,本次微博專案對Xcode進行了能滿足我們模仿要求的簡單設定。配置過程也就是修改info.plist檔案而已,點選“微博模擬”專案出現的設定頁面就是info.plist的圖形化介面。配置過程如下:

  • Bundle Identifier 設定
    Bundle Identifier 主要作用有app在上傳app store時為了區分不同程式 時使用,開發推送功能時需要,在這裡設定成YGWeibo.- - - - 。
  • Version 版本號
    以後迭代開發時,版本號必須比之前的大,在這裡不需要設定
  • Development Target
    選擇7.0以後的都可以
  • Devices
    選擇iPhone
  • Main Interface
    此次專案採用純程式碼建立,所以不需要載入storyboard,在這裡設定為空,並且把左側Main.Storyboard,ViewController.h,ViewController.m 檔案刪除。
  • Device orientation
    只選擇portrait
  • Status Bar Style
    選擇default後,勾選Hide Status Bar

這裡講一講,怎麼用純程式碼得到跟載入main.storyboard有相同效果的介面。首先蘋果應用程式的啟動步驟是這樣的,在一開啟時,首先進入main函式,main 函式內主要執行三個步驟,首先建立UIApplication物件,然後建立AppDelegate物件,並且成為UIApplication物件的代理屬性,然後開啟主執行緒迴圈,最後載入info.plist檔案,判斷是否有main.storyboard,如果有,就會載入main.storyboard。因為我們這裡才用純程式碼開發,所以info.plist就沒有main.storyboard檔案了,需要在AppDelegate.m裡的第一個代理方法中設定視窗,以及建立並載入檢視控制器,程式碼如下,但是此程式碼非最終的tabBarVC的設定程式碼,以後會有修改此處只做演示用。此程式碼就相當於載入Storyboard的步驟。


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // 建立視窗
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];

    // 為了展示效果 設定背景色為黃色
    self.window.backgroundColor = [UIColor yellowColor];

    // 建立tabBarViewController
    UITabBarController *tabBarVc = [[UITabBarController alloc] init]; 
    tabBarVc.view.backgroundColor = [UIColor redColor];

    // 管理子控制器
    // 首頁
    UIViewController *home = [[UIViewController alloc] init];
    home.view.backgroundColor = [UIColor greenColor];
    [tabBarVc addChildViewController:home];

    // 訊息
    UIViewController *message = [[UIViewController alloc] init];
    message.view.backgroundColor = [UIColor blueColor];
    [tabBarVc addChildViewController:message];

    // 發現
    UIViewController *discover = [[UIViewController alloc] init];
    discover.view.backgroundColor = [UIColor purpleColor];
    [tabBarVc addChildViewController:discover];

    // 我
    UIViewController *profile = [[UIViewController alloc] init];
    profile.view.backgroundColor = [UIColor lightGrayColor];
    [tabBarVc addChildViewController:profile];

    // 設定視窗的根控制器
    self.window.rootViewController = tabBarVc;

    // 顯示視窗
    [self.window makeKeyAndVisible];
    return YES;
}
  • 設定AppIcon
    直接拖拽素材資料夾內的AppIcon資料夾到Xcode裡Assets.xcassets內的AppIcon裡即可
  • 設定啟動圖片
    在專案General 設定裡面找到Launch Images Source 欄,點選後出現對話方塊,選擇migrate,然後點選其後的灰色按鈕,會發現自動跳轉到Brand Assets 欄內。開啟素材資料夾中的LaunchImages資料夾,拖拽檔案到Brand Assets 內,出現綠色加號後放開即可,最後刪除Launch Screen File 欄內的東西。
    但是這種方法不如直接載入Launch Screen.storyboard資料夾更強大,因為Launch Screen.storyboard可以展示更多的東西,且不需要美工出很多啟動圖片,因為其可以自動佈局以適應各種大小螢幕。如果不刪除Launch Screen.storyboard,則會優先載入Launch Screen.storyboard內容。

1.3 自定義tabBarController

1.3.1 更改AppDelegate.m

因為AppDelegate.m檔案以後會越來越大,應該自定義一個類專門用於建立和管理tabBarController。在新建檔案之前,要設定個字首,以方便區別和管理。選擇左邊欄微博模擬專案,找到最右邊欄有個“Class Prefix”欄,寫上你想起的字首名稱即可,如下圖所示。
設定專案字首
更改AppDelegate.m內容為如下程式碼:(首先要新建YGTabBarController)

#import "AppDelegate.h"
#import "YGTabBarController.h"
@interface AppDelegate ()

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    // 建立視窗

    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];

    //建立自定義tabbarcontroller

    YGTabBarController *tabBarVc = [[YGTabBarController alloc]init];

    // 設定視窗的根控制器

    self.window.rootViewController = tabBarVc;

    // 顯示視窗

    [self.window makeKeyAndVisible];
    return YES;
}

在此,提醒下UITabBarController內的view在一建立控制器的時候[[YGTabBarController alloc]init]就會載入View,並執行ViewDidLoad方法,所以其View不是懶載入的。但是一般的UIViewController的View是懶載入的。

1.3.2 新建YGTabBarController。

新建一個YGTabBarController類繼承自UITabBarController後,然後把之前在AppDelegate內建立與載入子控制器的程式碼封裝在YGTabBarController.m中,並把tabBarVc更改為self。
本小節主要任務就是為了程式碼的簡潔性,抽取兩個方法,一個是從ViewDidLoad中抽取設定tabBarController子控制元件的方法:

-(void)setUpAllChildViewController

因為每加一個子控制器所寫的程式碼都是類似的,所以又在上個方法內又抽取了設定一個子控制元件的方法。因為每個子控制器都要設定標題,顏色,圖片以及其他屬性,所以把這些屬性都設定為引數傳進到方法內。這裡提醒一下,如果引數中會傳入中文的話,一般把此引數放到最後,例如title引數。

- (void)setUpOneChildViewController:(UIViewController *)vc image:(UIImage *)image selectedImage:(UIImage *)selectedImage title:(NSString *)title

下面就要講如何設定tabBar按鈕上面的文字與圖片了。
首先tabBar上的按鈕是由對應的子控制器的tabBarItem屬性決定。匯入素材中tabBar資料夾拖入到專案中。設定按鈕title和image。在ios7之後,預設會把UITabBar上面的按鈕圖片渲染成藍色,但大多情況下藍色不是我們想要的顏色,我們想要讓tabBar用美工設計好的圖片顏色。更改的方法可以是,如圖片所示, 把每張帶有selected字元字尾的圖片的Render As 屬性設定為Original Image。

這裡寫圖片描述

或者用程式碼更改,在這裡我們就寫一個UIImage的分類——UIImage+Image.h/.m。目的是為了讓以後也方便設定圖片渲染。程式碼如下:

#import "UIImage+image.h"

@implementation UIImage (image)

+ (instancetype)imageWithOriginalName:(NSString *)imageName
{
    UIImage *image = [UIImage imageNamed:imageName];

    return [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
}

@end

這裡對上面的程式碼做下說明:為什麼要使用工廠方法(返回值為instancetype)?因為其預設識別是哪個類呼叫此方法,並返回該類的物件。

然後在setUpOneChildViewController方法裡設定按鈕標題等內容。程式碼如下:

 #pragma mark - 新增一個子控制器
- (void)setUpOneChildViewController:(UIViewController *)vc image:(UIImage *)image selectedImage:(UIImage *)selectedImage title:(NSString *)title
{
    vc.tabBarItem.title = title;
    vc.tabBarItem.image = image;
    vc.tabBarItem.badgeValue = @"10";
    vc.tabBarItem.selectedImage = selectedImage;
    [self addChildViewController:vc];
}

但是在設定字型顏色的時候你會發現,不能用self.tabBarItem.textColor 來設定標題顏色,因為UITabBarItem是模型而不是控制元件,模型是用來儲存資料以決定tabBar上按鈕的內容。只有控制元件才有textColor屬性,例如UILabel。所以通過觀察UITabBarItem的標頭檔案以及其父類的標頭檔案,發現可以用setTitleTextAttributes 方法 也就是富文字來設定標題顏色。富文字不僅可以設定控制元件的文字顏色,也可以設定字型空心,陰影,圖文混排等。通過UIKit框架內的NSAttributesString.h標頭檔案,可以查詢到設定富文字字典等key。這裡我們採用全域性方法+ initialize 來設定顏色。但在+load方法內也可以。但是兩者的呼叫事件不同,+initialize方法是在第一次使用這個類或者子類的時候呼叫。+load方法是在程式一啟動的時候就呼叫,然後把所有的類載入到記憶體,且先於main函式執行。
這裡寫圖片描述

initialize 程式碼如下:

+ (void)initialize
{
    // 這行程式碼是獲取所有的tabBarItem外觀標識,這樣就容易把不希望改動到外觀也更改了
    //  UITabBarItem *item = [UITabBarItem appearance];
    //一般採用帶 self的方法,這裡self就是指 YGTabBarController

    // 獲取當前這個類下面的所有tabBarItem
    UITabBarItem *item = [UITabBarItem appearanceWhenContainedIn:self, nil];
    NSMutableDictionary *att = [NSMutableDictionary dictionary];

    //這裡也可以用[att setObject:[UIColor orangeColor] forKey:NSForegroundColorAttributeName];
    //來設定富文字字典,兩種方法都可以。
    att[NSForegroundColorAttributeName] = [UIColor orangeColor];

    [item setTitleTextAttributes:att forState:UIControlStateSelected];
}

1.4 修改tabBar內部結構

在觀察實際微博介面會發現,tabBar中間有個用來發微博的加號按鈕。這就需要首先調整系統tabBar 結構,改變子控制元件位置,然後在中間加上加號按鈕 。系統的tabBar按鈕位置是不能改動的,所以智慧自定義一個YGTabBar,繼承自UITabBar。然後把系統TabBar替換成自定義的YGTabBar。程式碼如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    //新增子控制器
    [self setUpAllChildViewController];

    // 自定義tabBar
    YGTabBar *tabBar = [[YGTabBar alloc] initWithFrame:self.tabBar.frame];

    // 利用KVC更改readonly的屬性
    [self setValue:tabBar forKeyPath:@"tabBar"];
}

程式碼說明: 這裡有兩點需要注意,一要判斷在哪個方法裡去替換系統tabBar。經過測試發現,系統tabBar上的button是在執行完ViewDidLoad 和ViewWillAppear方法後才新增上去的。如下圖所示:

這裡寫圖片描述

從上如可以看到沒給方法執行的順序,所以我們要在新增tabBarButton前替換系統tabBar,這樣的話,tabBarButton就會新增到自定義的YZTabBar上面。

第二個問題就是,但是這樣賦值self.tabBar == tabBar 會出現錯誤。因為tabBar是readOnly屬性,不能這樣賦值。但是我們可以使用KVC賦值,如上面程式碼所示。

替換完系統tabBar之後,就要重寫YGTabBar.m 內的 layOutSubviews方法,來計算每個item的位置。在重寫之前先新增一個發微博按鈕。程式碼如下:

- (UIButton *)plusButton
{
    if (_plusButton == nil) {

        UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
        [btn setImage:[UIImage imageNamed:@"tabbar_compose_icon_add"] forState:UIControlStateNormal];
        [btn setImage:[UIImage imageNamed:@"tabbar_compose_background_icon_add"] forState:UIControlStateHighlighted];
        [btn setBackgroundImage:[UIImage imageNamed:@"tabbar_compose_button"] forState:UIControlStateNormal];
        [btn setBackgroundImage:[UIImage imageNamed:@"tabbar_compose_button_highlighted"] forState:UIControlStateHighlighted];

        // 預設按鈕的尺寸跟背景圖片一樣大
        // sizeToFit:預設會根據按鈕的背景圖片或者image和文字計算出按鈕的最合適的尺寸
        [btn sizeToFit];

        _plusButton = btn;

        [self addSubview:_plusButton];

    }
    return _plusButton;
}

重寫layoutsubviews方法,調整子控制元件位置,程式碼如下:

- (void)layoutSubviews
{

    [super layoutSubviews];
    CGFloat w = self.bounds.size.width;
    CGFloat h = self.bounds.size.height;

    CGFloat btnX = 0;
    CGFloat btnY = 0;
    CGFloat btnW = w / (self.items.count + 1);
    CGFloat btnH = self.bounds.size.height;
    int i = 0;
    // 調整系統自帶的tabBar上的按鈕位置
    for (UIView *tabBarButton in self.subviews) {
        // 判斷下是否是UITabBarButton
        if ([tabBarButton isKindOfClass:NSClassFromString(@"UITabBarButton" )]) {
            if (i == 2) {
                i = 3;
            }
            btnX = i * btnW;
            tabBarButton.frame = CGRectMake(btnX, btnY, btnW, btnH);
            i++;
        } 
    }
    // 設定新增按鈕的位置
    self.plusButton.center = CGPointMake(w * 0.5, h * 0.5);   
}

程式碼說明:在取出tabBar每個button子控制元件時,需要判斷類,可以利用NSClassFromString來根據一個字串得出其類名。在interface 內新增一個UIButton 屬性,並且懶載入,利用sizeToFit來預設按鈕尺寸和背景圖片一樣大。但是我們發現tabBar上的UIBadgeView (如圖所示)是繼承自UIView的,是系統自帶的,沒法通過設定圖片的方法更改。下一個微博將會講到如何設定自定義的badgeView。
這裡寫圖片描述

1.5 劃分結構

YGTabbar上現在有五個模組,每個模組都有自己的功能,如果像我們這樣直接建立每個模組的ViewController,就不能重寫每個控制器的viewDidLoad方法,也就沒法新增每個模組的各種功能了。這就需要我們為每個模組建立各自的MVC檔案,劃分結構如圖所示:

這裡寫圖片描述