iPhone:如何构建自己的 TabBar?

发布于 2024-10-16 08:28:51 字数 131 浏览 2 评论 0原文

因为我对普通 iPhone 标签栏无法提供的标签栏有一些要求,所以我需要构建自己的标签栏。

构建我自己的选项卡栏的最佳方法是什么,特别是如何以正确的方式在主视图控制器中添加/删除(显示/隐藏)视图,同时考虑到子视图的内存和最佳实践?

Because I have some requirements for a tabbar that the normal iphone tabbar cannot provide, I am needing to build my own.

What is the best way to build my own tabbar, specifically, how to add/remove (show/hide) views in my main view controller in the right way, taking into account memory and best practices for subviews?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

风启觞 2024-10-23 08:28:51

正如我在其他地方所说的,摆脱 UIKit 提供的核心导航类几乎永远不是一个好主意。您认为哪种类型的应用程序要求值得完全自定义的选项卡栏类?几乎总是可以通过子类化、分类或使用层来实现必要的自定义。

更新 1:以下是我在一些应用程序中为实现自定义标签栏所做的操作。

  1. 创建 UITabBar 的子类
  2. 向您的自定义子类添加一个方法,名为 -updateTabBarImageForViewControllerIndex:
  3. 在 Interface Builder 中,将选项卡栏控制器的选项卡栏的类更改为您的自定义子类
  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 就可以实现您想要实现的目标。导入 并利用图层内容。 :)

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

As I've stated elsewhere, it's almost never a good idea to get rid of the core navigational classes that are provided by UIKit. What type of application requirements do you have that you think merit a completely custom tab bar class? It's almost always possible to achieve the necessary customizations by either subclassing, categorizing, or making use of layers.

UPDATE 1: So here's what I did in some of my apps to get a custom tab bar implementation.

  1. Create a subclass of UITabBar
  2. Add a method to your custom subclass called something like -updateTabBarImageForViewControllerIndex:
  3. In Interface Builder, change the class of your tab bar controller's tab bar to your custom subclass
  4. In whatever class conforms to your tab bar controller's delegate (e.g., your app delegate), implement -tabBarController:shouldSelectViewController: and call -updateTabBarImageForViewControllerIndex: on your custom tab bar subclass

Basically, you want to notify your tab bar subclass every time the tab bar controller is about to switch view controllers. When this happens, determine what image you need to choose for your tab bar. You should have n images for your tab bar, one for the selected state of each tab. It's possible to actually fudge the implementation of UITabBarItem and just work with individual images, but it's a little more work.

// 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);
}

UPDATE 2: Now that I think about it more, you actually could (and should) get away with what you're trying to achieve without subclassing UITabBar at all. Import <QuartzCore/QuartzCore.h> and take advantage of layer contents. :)

// 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;
}
情释 2024-10-23 08:28:51

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

如果你买不起那么多内存(但这不太可能),那么你可以将 NSDictionary 存储在数组中,而不是视图控制器。当用户点击选项卡栏项时,您只需卸载前一个视图控制器并使用该字典中的参数创建新的视图控制器。或者您可以使用一些自定义容器类来代替字典。

It really depends on your application. If you can afford to keep in memory all view controllers, that assigned to your tabbar, then you can use a simple array, that would store all appropriate view controllers, and you show them using the index in that array.
It is also a good idea to create your custom view controller, that would store it's own tabbar image (and/or title). And your tabbar would take all that values from there.

If you can't afford so much memory (but it's not very possible) then you can store NSDictionary in the array, and not view controllers. And when user taps on the tabbar item you just unload the previous view controller and create the new one, with parameters from that dictionary. Or instead of the dictionary you can use some custom container class.

故乡的云 2024-10-23 08:28:51

这两个公认的答案在 iOS5 中崩溃了。相反,我所做的是保留自定义选项卡栏子类,并仅保留此方法不变:

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

然后在 MainWindow.xib 中,我创建了一个自定义视图,其中 imageview 作为背景,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;
}

This two accepted answers break in iOS5. What I did instead was to keep the custom tab bar subclass, and leave only this method intact:

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

Then in MainWindow.xib, I created a custom view with an imageview as the background and UIButtons as the tab bar items.

In the TabController delegate, I update the buttons' selected states.

- (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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文