Reusable button bars?让我在这里完成了部分工作,但现在我在“后退按钮”要求方面遇到了麻烦。
我需要一个布局解决方案:
- 适用于 iOS 5.0 和 6.0
- 顶部有一个带有多个按钮的自定义 View ;该 View 应该可以在每个屏幕(场景)上重复使用,而不是在 Interface Builder 中为每个场景手动复制按钮。
- 在顶部自定义 View 中有一个自定义“后退”按钮。根据我必须实现的设计,我不能只使用默认导航栏
- 与 UINavigationController 配合良好;当用户点击“后退”按钮时,主视图 Controller (带有按钮栏)应该保留,但代表实际场景内容的 subview Controller 应该返回到前一个场景。
当前的问题是“后退”按钮不会更改子 Controller - 它会更改父 Controller ,返回到带有按钮栏的场景之前的上一个场景。我已经尝试过几种不同的方法。我不确定是我做得不对,还是做不到。
一种可能性是实现我自己的“后退”功能,保留一堆 subview Controller 并在用户点击“后退”时手动更改它们。然而,与使用 UINavigationController 相比,这很尴尬,而且设计很糟糕。
也许我走错了路。我无法接受在 Interface Builder 中的每个场景中复制按钮栏...但也许我应该以编程方式创建它,然后我可以轻松地从每个场景调用该代码。然后我会有“普通” View Controller ,并且使用 UINavigationController 会更容易。但在我走这条路并完全废弃我迄今为止所拥有的东西之前,我想看看是否还有其他方法。
以下是我的解决方案的某些部分的概述:
我创建了一个 ButtonBarController,用一个用于我想要的按钮的 UIView 和一个用于内容 Pane 的 UIView 来布局 Storyboard。我还在后退按钮之上分层放置了一个带有应用程序 Logo 的按钮(用于转到应用程序的主屏幕)。
然后我为其他每个屏幕创建了一个 Controller 。在这些子屏幕/ subview Controller 中,我首先添加一个正确大小的 UIView 以适合我的内容 Pane ,然后添加我想要的所有其他控件。我让所有这些 subview Controller 都继承自另一个 Controller ,该 Controller 负责一些常见任务,例如获取对按钮栏 Controller 的引用,以及帮助调整 3.5 英寸与 4 英寸屏幕的 View 大小的代码。
我创建了一个changeToControllerWithIndex方法;当应用程序加载时,当用户单击主按钮栏中的某个按钮来更改场景时,或者当场景中发生任何需要更改另一个场景时,我会调用此方法。我重载此方法以提供两条附加信息:为 NSDictionary 提供 subview Controller 所需的任何附加信息,并告诉它这是否是顶级场景,或者我们是否需要后退按钮。
(注意:在身份检查器中为这些 subview Controller 设置 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];
}
}
}
然后我有一个重载方法来设置每个单独的 View Controller ......有些需要比其他更多的准备。
- (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;
}
我提到了管理“后退”导航的困难。上面的代码确保导航 Controller 维护正确的“后退”历史记录,每当我们使用按钮栏按钮之一更改屏幕时都会重新开始。当我们使用子 Controller 内的按钮从一个场景导航到另一个场景时,我们可以这样返回:
- (IBAction)backButtonPressed:(id)sender {
[childNavigationController popViewControllerAnimated:YES];
if ([[childNavigationController viewControllers] count] <= 1) {
//Root view
[homeButton setHidden:NO];
[backButton setHidden:YES];
}
}
最佳答案
我认为您需要至少实现一个自定义容器 View Controller - Root View Controller 。那将是托管自定义按钮栏的地方。在按钮栏下方,您将添加一个 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];
}
关于objective-c - 带有自定义后退导航按钮的自定义按钮栏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13057229/