1. 程式人生 > >獻給初學iOS的小盆友們——微博app專案開發之四設定導航功能

獻給初學iOS的小盆友們——微博app專案開發之四設定導航功能

本節課我們主要想實現導航條的導航功能,順便要解決一些bug。學到的知識點包括控制器的轉換,和xib的使用。

主要內容

  • 導航條導航功能
  • 設定導航條內容
  • 解決導航條bug

本節資料下載

4.1 導航條導航功能,並隱藏tabBar

我們這裡主要學些,如何在點選首頁導航條的右邊按鈕後顯示新的控制器,而且在新控制器上隱藏tabBar,並且在新控制器的右邊按鈕設定一鍵返回根控制器的功能。
首先建立一個新的控制器類YGOneViewController,繼承自UIViewController。然後建立一個xib檔案,建立方法如下圖所示:
這裡寫圖片描述

這裡要讓xib的名字與對應類的名字相同,取名為YGOneViewController,因為系統會首先為控制器預設載入相同名字的xib。然後在選中的xib檢視內,新增一個跳轉按鈕,可以跳轉到下一個控制器,而且要把xib繫結到對應的YGOneViewController類上。如下圖所示:
這裡寫圖片描述


最後不要忘記右鍵點選file Owner圖示,然後把view與xib的檢視連線。如下圖所示:
這裡寫圖片描述

這樣就可以修改YGHomeViewController裡的pop方法了,程式碼如下:

- (void)pop
{
        //建立新的控制器
    YGOneViewController *one = [[YGOneViewController alloc]init];

        //跳轉到新的控制器
    [self.navigationController pushViewController:one animated:YES];
}

程式碼說明:在這裡,建立檢視控制器的init 方法與initWithNibName:nil 方法時一樣的,因為系統預設載入相同名字的xib檔案。init底層就會呼叫initWithNibName方法。

但是這時候如果執行專案的話,會發現在新的控制器上tabBar沒有隱藏,所以假設我們在pop方法內新增一下程式碼:

//隱藏tabBar
// 前提條件,隱藏系統自帶的tabBar
one.hidesBottomBarWhenPushed = YES;

可以發現,tabBar並沒有被隱藏,原來這個程式碼只能隱藏系統自帶的tabBar,並不能隱藏我們自定義的YGTabBar。不要慌,我們思考下便發現,我們只需要把自定義的YGTabBar加到系統的tabBar上就可以啦,但是要注意加上之後,要在viewWillAppear內刪除tabBar自帶的UITabBarButton按鈕。setUpTabBar更改程式碼如下:

-(void)setUpTabBar
{
        // 自定義tabBar
        //YGTabBar *tabBar = [[YGTabBar alloc] initWithFrame:self.tabBar.frame];
       //修改後
        YGTabBar *tabBar = [[YGTabBar alloc] initWithFrame:self.tabBar.bounds];

        tabBar.backgroundColor = [UIColor whiteColor];

        // 設定代理
        tabBar.delegate = self;

        // 給tabBar傳遞tabBarItem模型
    NSLog(@"this is items%@",self.items);
        tabBar.items = self.items;

        // 新增自定義tabBar
        //[self.view addSubview:tabBar];
        //修改後
        [self.tabBar addSubview:tabBar];
        // 移除系統的tabBar
       // [self.tabBar removeFromSuperview];
}

程式碼說明,首先解釋為何要把frame更改為bounds。因為當我們把自定義tabBar加到系統tabBar上時,參考座標系就時系統的tabBar,而不是系統tabBar的frame。假設系統tabBar在視窗內縱座標為Y,如果仍然使用frame的話,載入到系統tabBar上的自定義tabBar的縱座標也為Y了,就離開了視窗,不能被顯示出來了。
移除系統tabBarButton的程式碼如下:

-(void)viewWillAppear:(BOOL)animated
{
    //移除系統的UITabBarButton
    for(UIView *tabBarButton in self.tabBar.subviews)
    {
        if ([tabBarButton isKindOfClass:NSClassFromString(@"UITabBarButton")]) {
            [tabBarButton removeFromSuperview];
        }
    }
}

因為我們在之前就發現,系統的UITabBarButton不是在viewDidLoad內新增到tabBar 上的,而是其之後新增的,在viewWillAppear內就已經可以打印出所有的UITabBar Button了,具體在哪裡新增的,也沒有精準的試驗出來,只能給個範圍。但是知道在viewWillAppear內可以移除就滿足要求了。

移除前的檢視結構如下圖:
這裡寫圖片描述

移除後的檢視結構如下圖:
這裡寫圖片描述

經過對比可以發現,系統自帶的UITabBarButton確實被移除了。如果在此時執行專案,就會發現tabBar確實能被隱藏了。

4.2 設定跳轉後的導航條內容

當點選首頁導航條右側按鈕後,會出現的新的導航條,這裡我們也需要設定其內容,程式碼就很簡單了:

-(void)viewDidLoad
{
    //設定導航條左邊
    self.navigationItem.leftBarButtonItem = [UIBarButtonItem barButtonItemWithImage:[UIImage imageNamed:@"navigationbar_back"] highImage:[UIImage imageNamed:@"navigationbar_back_highlighteds"] target:self action:@selector(backToPre) forControlEvents:UIControlEventTouchUpInside];

    //設定導航條右邊
    self.navigationItem.rightBarButtonItem = [UIBarButtonItem barButtonItemWithImage:[UIImage imageNamed:@"navigationbar_more"] highImage:[UIImage imageNamed:@"navigationbar_more_highlighteds"] target:self action:@selector(backToRoot) forControlEvents:UIControlEventTouchUpInside];
}
-(void)backToPre
{
    [self.navigationController popViewControllerAnimated:YES];
}
-(void)backToRoot
{
    [self.navigationController popToRootViewControllerAnimated:YES];
}

為了擴充套件知識,我們再次新建一個檢視控制器YGTwoViewController,且勾選建立xib檔案。然後我們在YGOneViewController內建立跳轉到第二個控制器的方法,採用連線發,建立程式碼如下:

@implementation YGOneViewController
- (IBAction)jumpToTwoController:(id)sender {
    YGTwoViewController *two = [[YGTwoViewController alloc]init];
    [self.navigationController pushViewController:two animated:YES];
}

可以發現,第二個控制器的導航條跟我們設定的不一樣,我們又得從新設定其導航條內容。如果一直貼上拷貝的話,會很麻煩,真實的專案中,會有很多層控制器,一層層拷貝肯定不現實。我們可以重寫導航控制器YGNavigationController的push方法,其程式碼如下:

-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
        //設定非根控制器的導航條內容
    if(self.viewControllers.count !=0){
            //設定導航條左邊
            viewController.navigationItem.leftBarButtonItem = [UIBarButtonItem barButtonItemWithImage:[UIImage imageNamed:@"navigationbar_back"] highImage:[UIImage imageNamed:@"navigationbar_back_highlighteds"] target:self action:@selector(backToPre) forControlEvents:UIControlEventTouchUpInside];

            //設定導航條右邊
            viewController.navigationItem.rightBarButtonItem = [UIBarButtonItem barButtonItemWithImage:[UIImage imageNamed:@"navigationbar_more"] highImage:[UIImage imageNamed:@"navigationbar_more_highlighteds"] target:self action:@selector(backToRoot) forControlEvents:UIControlEventTouchUpInside];
    }
    [super pushViewController:viewController animated:animated];

}
-(void)backToPre
{
    [self popViewControllerAnimated:YES];
}
-(void)backToRoot
{
    [self popToRootViewControllerAnimated:YES];
}

代買說明: 只要覺得系統自帶方法不滿足要求,我們就可以重寫系統方法。這裡為什麼要先做判斷呢,是因為一開始執行的initWithRootViewController底層會呼叫push,把根控制器壓入棧,如果直接這樣設定就會把根控制器,也就是首頁的導航條內容也給更改了。

4.3 解決跳轉根控制器後tabBar的bug

但是如果把導航條上的返回按鈕覆蓋了,滑動返回功能就沒有了,所以要實現滑動返回功能就要清空返回手勢代理,而且為了在返回到根控制器時,還原滑動手勢代理,需要執行navigation的一個代理方法,來判斷何時清空手勢代理:

//導航控制器跳轉完成時呼叫
-(void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    if (viewController == self.viewControllers[0]) {
        //還原滑動返回手勢
        self.interactivePopGestureRecognizer.delegate=_popDelegate;
    }else
    {
        //實現滑動返回功能,清空滑動返回手勢的代理,就能實現滑動
        self.interactivePopGestureRecognizer.delegate = nil;
    }
}

程式碼說明:這裡的popDelegate只是用來儲存手勢代理,用於還原時使用。

還有一個比較大的bug,當我們跳轉到第二個控制器的時候,然後點選導航條右邊按鈕,返回根控制器,會發現系統的tabBar又被新增上了。如下圖所示:

這裡寫圖片描述

目前這個bug導致的原因我也沒有搞清楚,但是解決的方法還是有的,只需要找準地方把它像之前那樣刪除就好了。可以發現,navigationController有兩個代理方法,一個是即將顯示的時候執行,一個是已經顯示的時候執行,我們可以在即將顯示根控制器的時候,把系統的tabBarButton 給刪除掉。程式碼如下:

//當導航控制器即將顯示的時候呼叫
-(void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
    //獲取住視窗
    UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
    //獲取tabBarViewController
    UITabBarController *tabBarVc = (UITabBarController*)keyWindow.rootViewController;
    //移除系統的UITabBarButton
    for(UIView *tabBarButton in tabBarVc.tabBar.subviews)
    {
        if ([tabBarButton isKindOfClass:NSClassFromString(@"UITabBarButton")]) {
            [tabBarButton removeFromSuperview];
        }
    }
}

至此,tabBar和導航條內容和功能都講的差不多了,下面就可以講新內容了。首先是新特性介面的搭建,然後是微博授權頁面都搭建。好好練習吧。