2012-10-24 262 views
0

Reusable button bars?讓我在這裏的一部分,但現在我遇到了「後退按鈕」的要求的問題。自定義按鈕欄與自定義後退導航按鈕

我需要一個佈局的解決方案:

  • 將在iOS 5.0工作,6.0
  • 有在幾個按鈕上的自定義視圖;這個視圖應該可以在每個屏幕(場景)中重複使用,而不是在Interface Builder中爲每個場景手動複製按鈕。
  • 在該自定義視圖中有一個自定義「後退」按鈕。隨着我必須實現的設計,我不能只使用默認導航欄
  • 與UINavigationController一起使用;當用戶點擊「後退」按鈕時,主視圖控制器(帶按鈕欄)應該保留,但代表實際場景內容的子視圖控制器應該返回到前一個場景。

目前的問題是,「後退」按鈕不會更改子控制器 - 它會更改父控制器,使用按鈕欄返回到場景之前的前一個場景。我已經嘗試了這幾種不同的方式。我不確定我是否做得不對,或者做不到。

一種可能性是實現我自己的「後退」功能,保留一堆子視圖控制器,並在用戶點擊「後退」時手動更改它們。然而,這與使用UINavigationController相比很尷尬,設計也很糟糕。

也許我會用這個錯誤的方式。我無法接受在Interface Builder中的每個場景中重複按鈕欄......但也許我應該以編程方式創建它,然後我可以輕鬆地從每個場景調用該代碼。然後我會有「正常」的視圖控制器,並使用UINavigationController會更容易。但是,在我走完這條路線並徹底廢除迄今爲止我所擁有的東西之前,我想看看是否有另一種方式。


這裏是我的解決方案的某些部分的概述:

我創建了一個ButtonBarController,鋪設了故事板與我想要的按鈕一個UIView,併爲內容窗格一個UIView。我還在後退按鈕頂部放置了一個帶有應用程序徽標的按鈕(以轉到應用程序的主屏幕)。

然後我爲每個其他屏幕創建了一個控制器。在這些子屏幕/子視圖控制器中,我會首先添加一個正確大小的UIView以適應我的內容窗格,然後添加所需的其他所有控件。我將所有這些子視圖控制器從其他控制器繼承,這些控制器負責處理一些常見任務,例如獲取對按鈕欄控制器的引用,以及用於幫助調整3.5「與4」屏幕視圖大小的代碼。

我創建了一個changeToControllerWithIndex方法;我在應用程序加載時,當用戶單擊主按鈕欄中的一個按鈕以更改場景時,或在需要另一個場景更改的場景中發生任何事情時,我會調用此方法。我重載這個方法來提供兩個額外的信息:提供一個NSDictionary和子視圖控制器需要的任何額外的信息,並告訴它它是一個頂層場景還是我們需要一個後退按鈕。

(注意:在Identity Inspector中爲這些子視圖控制器設置Storyboard ID很重要。我一直不小心設置在屬性檢查器的標題代替)

- (void)changeToControllerWithIndex:(NSInteger)index { 
    [self changeToControllerWithIndex:index withPayload:nil isRootView:YES]; 
} 

// This is the method that will change the active view controller and the view that is shown 
- (void)changeToControllerWithIndex:(NSInteger)index withPayload:(id)payload isRootView:(BOOL)isRootView 
{ 
    if (YES) { 
     self.index = index; 

     // The code below will properly remove the the child view controller that is 
     // currently being shown to the user and insert the new child view controller. 
     UIViewController *vc = [self setupViewControllerForIndex:index withPayload:payload]; 

     if (isRootView) { 
      NSLog(@"putting navigation controller in"); 
      childNavigationController = [[UINavigationController alloc] initWithRootViewController:vc]; 
      [childNavigationController setNavigationBarHidden:YES]; 
      [self addChildViewController:childNavigationController]; 
      [childNavigationController didMoveToParentViewController:self]; 

      if (self.currentViewController){ 
       [self.currentViewController willMoveToParentViewController:nil]; 

       [self transitionFromViewController:self.currentViewController toViewController:childNavigationController duration:0 options:UIViewAnimationOptionTransitionNone animations:^{ 
        [self.currentViewController.view removeFromSuperview]; 
       } completion:^(BOOL finished) { 
        [self.currentViewController removeFromParentViewController]; 
        self.currentViewController = childNavigationController; 
       }]; 
      } else { 
       [self.currentView addSubview:childNavigationController.view]; 
       self.currentViewController = childNavigationController; 
      } 

      [self.currentView addSubview:childNavigationController.view]; 

      //We are at the root of the navigation path, so no back button for us 
      [homeButton setHidden:NO]; 
      [backButton setHidden:YES]; 
     } else { 
      //Not a root view -- we're in navigation and want a back button 

      [childNavigationController pushViewController:vc animated:NO]; 

      [homeButton setHidden:YES]; 
      [backButton setHidden:NO]; 
     } 
    } 
} 

然後,我有一個重載的方法來設置每個單獨視圖控制器......一些需要比別人多一點準備。

- (UIViewController *)setupViewControllerForIndex:(NSInteger)index { 
    return [self setupViewControllerForIndex:index withPayload:nil]; 
} 

// This is where you instantiate each child controller and setup anything you need on them, like delegates and public properties. 
- (UIViewController *)setupViewControllerForIndex:(NSInteger)index withPayload:(id)payload { 
    UIViewController *vc = nil; 
    if (index == CONTROLLER_HOME){ 
     vc = [self.storyboard instantiateViewControllerWithIdentifier:@"Home"]; 
    } else if (index == CONTROLLER_CATEGORIES){ 
     SAVECategoryViewController *child = [self.storyboard instantiateViewControllerWithIdentifier:@"Categories"]; 
     if (payload) { 
      child.currentCategory = [(NSNumber *) [(NSDictionary *)payload objectForKey:ATTRIBUTE_CAT_ID] integerValue]; 
     } else { 
      child.currentCategory = CATEGORY_ALL; 
     } 
     vc = child; 
    } //etc for all the other controllers... 
    payload = nil; 

    return vc; 
} 

我提到了管理「後退」導航的困難。上述代碼可確保導航控制器保持適當的「後退」歷史記錄,每當我們使用其中一個按鈕欄按鈕更改屏幕時,都會重新開始。當我們用一個子控制器內的按鈕從現場到現場進行導航,這是我們可以回去:

- (IBAction)backButtonPressed:(id)sender { 
    [childNavigationController popViewControllerAnimated:YES]; 
    if ([[childNavigationController viewControllers] count] <= 1) { 
     //Root view 
     [homeButton setHidden:NO]; 
     [backButton setHidden:YES]; 
    } 
} 

回答

1

我認爲你需要實現至少一個自定義的容器視圖控制器 - 根視圖控制器。這將是主持自定義按鈕欄的人。在按鈕欄下方,您將添加一個UINavigationController來管理您的其他VC。看看這個初學者:

@implementation RootVC 
//... 

- (void)viewDidLoad 
{ 
    self.navVC = [[UINavigationController alloc] initWithRootViewController:someOtherVC]; 
    self.navVC.navigationBarHidden = YES; 
    self.navVC.view.frame = ...; 

    [self addChildViewController:self.navVC]; 
    [self.view addSubview:self.navVC.view]; 
    [self.navVC didMoveToParentViewController:self]; 
} 

- (void)backButtonTouched:(UIButton *)button 
{ 
    [self.navVC popViewControllerAnimated:YES]; 
}