iPhone:我该如何构建自己的TabBar?

4
因为我对普通的 iPhone 标签栏有一些要求,它无法提供,所以我需要构建自己的标签栏。
如何构建自己的标签栏是最佳方式,具体来说,如何以正确的方式在我的主视图控制器中添加/删除(显示/隐藏)视图,考虑到子视图的内存和最佳实践?
3个回答

7
正如我在其他地方所说的那样,几乎从来不删除由UIKit提供的核心导航类是一个好主意。你有什么类型的应用程序要求,认为需要完全自定义的选项卡栏类?通常可以通过子类化、分类或使用图层来实现必要的自定义。 更新1:以下是我在一些应用程序中实现自定义选项卡栏的方法:
  1. 创建一个UITabBar的子类
  2. 添加一个名为-updateTabBarImageForViewControllerIndex:的自定义子类方法
  3. 在界面构建器中,将您的选项卡栏控制器的选项卡栏类更改为您的自定义子类
  4. 在任何符合您的选项卡栏控制器委托的类中(例如,您的应用程序委托),实现-tabBarController:shouldSelectViewController:并在您的自定义选项卡栏子类上调用-updateTabBarImageForViewControllerIndex:
基本上,您希望在选项卡栏控制器即将切换视图控制器时通知您的选项卡栏子类。当这种情况发生时,确定您需要选择哪个图像作为选项卡栏。您应该为选项卡栏拥有n个图像,每个选项卡的选定状态都有一个图像。实际上可以欺骗UITabBarItem的实现,并只使用单独的图像,但这需要更多的工作。
// MyAppDelegate.m

- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{
    // Determine the index based on the selected view controller

    NSUInteger viewControllerIndex = ...;

    [(MyTabBar *)tabBarController.tabBar updateTabBarImageForViewControllerIndex:viewControllerIndex];

    return YES;
}

// MyTabBar.m

- (void)updateTabBarImageForViewControllerIndex:(NSUInteger)index
{
    // Determine the image name based on the selected view controller index

    self.selectedTabBarImage = [UIImage imageNamed:...];

    [self setNeedsDisplay];
}

- (void)drawRect:(CGRect)rect
{
    CGContextDrawImage(UIGraphicsGetCurrentContext(), rect, self.selectedTabBarImage.CGImage);
}
更新2: 现在我想了想,你实际上可以(并且应该)完全不必子类化UITabBar就能够实现你想要的目标。导入<QuartzCore/QuartzCore.h>并利用图层内容即可。 :)
// MyAppDelegate.m

- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{
    // Determine the image name based on the selected view controller

    CGImageRef newTabBarImageRef = [[UIImage imageNamed:...] CGImage];
    tabBarController.tabBar.layer.contents = (id)newTabBarImageRef;

    return YES;
}

实际上,关于UITabBar[Controller],苹果公司真的不喜欢你去子类化它。虽然可以这样做,但通常会失败,因为他们在里面设置了一堆assert()来阻止你这样做。当我在开发论坛上询问时,答案是“自己动手写”。(事实上,我没有这样做,但一路上确实经历了痛苦和折磨。) - Amy Worrall
如果你只是通过覆盖“-drawRect:”来自定义样式,那么子类化没有任何问题。是的,你不想覆盖任何改变基础逻辑的方法,但是如果你适当地使用它,子类化是无害的。无论如何,这就是为什么我建议尽可能使用图层。不需要子类或分类。 - CIFilter
玩弄-drawRect使您可以自定义选项卡栏项目的覆盖颜色和文本颜色? - Nic Hubbard
-drawRect: 方法中,您可以使用任何 Core Graphics 绘图例程来绘制线条、形状、渐变、文本和图像。最简单的方法是为每个选项卡栏项目使用图像,以完全覆盖标准选项卡栏。请参考我创建的 Tim McGraw 应用程序的截图:http://itunes.apple.com/us/app/tim-mcgraw/id341650507?mt=8 这是否与您对选项卡栏的需求一致? - CIFilter
嗨。抱歉,我离开家已经一段时间了,我的旧项目文件都在那里。大意是你需要创建一个UITabBar子类并重写“-drawRect:”方法以绘制背景图像。然后创建一个UITabBarItem子类并要么重写“-initWithTitle:image:tag:”方法以绘制完全自定义的图像,要么创建一个新方法以获取UIImage并将其绘制为选项卡条目的内容。当我能够访问我的旧项目时,我会再与你联系。或者看看这个链接:http://blog.theanalogguy.be/2010/10/06/custom-colored-uitabbar-icons/ - CIFilter
显示剩余7条评论

0

这两个被接受的答案在iOS5中出现问题。相反,我所做的是保留自定义选项卡栏子类,并仅保留此方法:

- (void)drawRect:(CGRect)rect
{
   CGContextDrawImage(UIGraphicsGetCurrentContext(), rect, nil);
} 

接着在MainWindow.xib中,我创建了一个自定义视图,其中UIImageView作为背景,而UIButtons则用作选项卡栏目。

在TabController代理中,我更新按钮的选中状态。

- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController:(UIViewController *)viewController
{
 // Determine the index based on the selected view controller

 UIButton *newBtn;

 if(viewController == homeVC) {
   ...
 }
 // Update the buttons
 newBtn.selected = YES;
 _selectedTabBtn.selected = NO;
 _selectedTabBtn = newBtn;

 return YES;
}

在iOS5中,它们允许您自定义选项卡栏,因此这不再是一个问题。 - Nic Hubbard
你有新文档的链接吗?在UITabBarItem、UITabBar或UITabBarController中找不到任何内容。 - oohaba
2
有新的backgroundImage、selectedImageTintColor、selectionIndicatorImage和tintColor属性。在XCode 4.2文档中查找,然后您将在iOS 5库中看到它。 - Nic Hubbard
啊,我现在明白了。那个方法可行,但我的解决方案对于那些想要向后兼容iOS4的人仍然可能有用。 - oohaba

0

这取决于您的应用程序。如果您有足够的内存来保留分配给选项卡栏的所有视图控制器,那么可以使用一个简单的数组来存储所有适当的视图控制器,并使用该数组中的索引显示它们。 创建自定义视图控制器也是一个好主意,它将存储自己的选项卡栏图像(和/或标题)。您的选项卡栏将从那里获取所有这些值。

如果您无法承受如此多的内存(但这不太可能),则可以在数组中存储NSDictionary而不是视图控制器。当用户点击选项卡栏项目时,您只需卸载先前的视图控制器并创建新的视图控制器,其中包含该字典中的参数。或者,您可以使用一些自定义容器类来代替字典。


普通的UITabBar是否会将所有视图加载到内存中? - Nic Hubbard
1
是的。从文档中 - (void)setViewControllers:(NSArray *)viewControllers animated:(BOOL)animated,所以你首先必须创建视图控制器。 - Max
你已经完成了 UIKit 的 95% 工作,通过制作自己的选项卡栏(控制器)。为什么不通过一些简单的子类化或层内容操作来完成剩下的5%工作呢? - CIFilter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接