2012-10-24 265 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]; 
}