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];
}
}