【问题标题】:How to connect two different Tab bar icons to same view controller with storyboard?如何使用情节提要将两个不同的标签栏图标连接到同一个视图控制器?
【发布时间】:2013-02-05 14:58:05
【问题描述】:

我在一个包含 6 个项目的 iPad 应用程序中有一个标签栏控制器。当您点击它们时,其中两个图标将指向同一个视图控制器。这个视图控制器有一个它将显示的项目列表,它会根据您点击的标签栏图标而略有变化。

如何使用故事板进行设置?可以将关系两次拖动到同一个视图控制器,但它只在选项卡栏上显示两个相同的图标。我希望这两个选项具有不同的图标和名称。

【问题讨论】:

    标签: ios ipad uitabbarcontroller storyboard uistoryboard


    【解决方案1】:

    我相信您最好创建两个单独的视图控制器并将它们分别放置在选项卡栏控制器中,尤其是当它们要加载不同的数据时。您可以将同一个视图控制器多次放入 Tab Bar Controller,但就设计和操作方式而言,这样做没有多大意义。

    【讨论】:

    • 它是相同的数据,只是不同的子集。所以它们看起来 100% 相同
    • 明白了,但是 Tab Bar Controller 实际上只是用来在不同的视图控制器之间进行选择,而不是数据子集。
    【解决方案2】:

    我不认为你可以用 UITabBarController 做你想做的事情。如果需要,您可以添加同一视图控制器类的两个不同实例。否则,您将不得不在常规 UIViewController 中添加一个标签栏,并编写您自己的逻辑来在控制器之间切换。

    【讨论】:

      【解决方案3】:

      如您所见,您可以在情节提要中设计一次视图控制器,但不能多次将其与标签栏控制器关联。

      您可以做的是在身份检查器中为其分配一个标识符,然后在运行时您可以使用方法-[UIStoryboard instantiateViewControllerWithIdentifier:] 实例化视图控制器的第二个副本。您可以使用 -[UITabBarController setViewControllers:animated:] 将第二个副本插入到选项卡控制器中

      【讨论】:

        【解决方案4】:

        当我尝试使用 4 个选项卡项实现选项卡栏控制器视图时,我遇到了与您相同的问题,并且每个选项卡项都重用相同的视图控制器,并且这 4 个项目的自定义逻辑是通过属性设置的标签栏控制器调用viewDidLoad。让我向您展示我所做的如下:

        1.创建一个带有 4 个视图控制器的标签栏控制器

        打开故事板,从对象库中拖出Tab Bar Controller。并将另外 2 个view controller 也拖到故事板上。

        记得在标签栏控制器和两个新的视图控制器之间建立一个链接。

        2。为 4 选项卡视图创建重用视图控制器

        创建一个新的 cocoa touch 类,命名为 ViewController,并在 @interface 部分创建自定义属性。这些属性会在标签栏控制器viewDidLoad方法中设置,所以4个标签视图会使用同一个视图控制器,但属性不一样。

        #import <UIKit/UIKit.h>
        
        @interface ViewController : UIViewController <UITableViewDataSource, UITableViewDelegate>
        
        // Define your customisation properties here, so that you can set it in the tab bar controller.
        @property (assign, nonatomic) UITableViewCellStyle style;
        
        @end
        

        4.创建UITabBarController的视图控制器子类

        创建一个新的 Cocoa Touch 类,命名为UITabViewController,并使其成为UITabBarController 的子类,并符合UITabBarControllerDelegate

        对于我的情况,我需要在 4 个不同的选项卡中显示具有不同 4 单元格样式的表格视图,因此我将在选项卡栏控制器中设置 viewControllerstyle 属性以实现我的目标。

        UITabViewController.h

        #import <UIKit/UIKit.h>
        
        @interface UITabViewController : UITabBarController <UITabBarControllerDelegate>
        @end
        

        UITabViewController.m

        #import "UITabViewController.h"
        
        @interface UITabViewController ()
        
        @end
        
        @implementation UITabViewController
        
        - (void)viewDidLoad {
            // Make UITabViewController as the delegate of UITabBarController
            self.delegate = self;
        
            [super viewDidLoad];
        
            // Set-Up the UITableCell style for each tab item
            [self.viewControllers enumerateObjectsUsingBlock:^(id viewController, NSUInteger idx, BOOL *stop){
                UITableViewCellStyle style;
                switch (idx) {
                    case 0:
                        style = UITableViewCellStyleDefault;
                        break;
                    case 1:
                        style = UITableViewCellStyleSubtitle;
                        break;
                    case 2:
                        style = UITableViewCellStyleValue1;
                        break;
                    case 3:
                        style = UITableViewCellStyleValue2;
                        break;
                    default:
                        style = UITableViewCellStyleDefault;
                        break;
                }
        
                SEL selector = @selector(setStyle:);
        
                if([viewController respondsToSelector:selector]){
                    NSInvocation *invk = [NSInvocation invocationWithMethodSignature:[viewController methodSignatureForSelector:selector]];
                    [invk setSelector:selector];
                    [invk setTarget:viewController];
        
                    [invk setArgument:&style atIndex:2];
                    [invk invoke];
                }
            }];
        }
        

        或者如果您需要在用户选择不同的选项卡项时设置自定义属性,那么您可以在UITabViewController@implementation 部分添加一个新的委托方法:

        - (void)tabBarController:(UITabBarController *)tabBarController didSelectViewController:(UIViewController *)viewController{
            // Check whether the view controller responds to the property setter method
            SEL selector = @selector(setMyProperty:);
        
            if([viewController respondsToSelector:selector]){
                // Call the setter method with NSInvocation
                NSInvocation *invk = [NSInvocation invocationWithMethodSignature:[viewController methodSignatureForSelector:selector]];
                [invk setSelector:selector];
                [invk setTarget:viewController];
        
                [invk setArgument:&argument atIndex:2];
                [invk invoke];
            }
        }
        

        【讨论】:

          【解决方案5】:

          我遇到了类似的问题,很容易解决。

          在情节提要中创建一个 TabBarController。

          在每个选项卡中分配一个导航控制器。

          将所有导航控制器设置为根视图控制器,这是您要在它们之间共享的一个视图控制器。

          在您的视图控制器中,在 ViewDidLoad 中,基于 tabBarController.selectedIndex 创建一个条件,以便根据所选选项卡自定义视图控制器。像这样的:

          override func viewDidLoad() {
              super.viewDidLoad()
              if let selectedTabIndex = tabBarController?.selectedIndex {
                     switch selectedTabIndex:
                     case 0: // Customize ViewController for tab 1
                     case 1: // Customize ViewController for tab 2
                     case 2: // Customize ViewController for tab 3
                     default: break
          
          }
          

          【讨论】:

            【解决方案6】:

            我可以通过在 viewDidLoad 中设置标签标题来实现这一点。我为同一个视图控制器创建了 2 个关系。然后我将栏项目标题设置为“未设置”。最后,我设置viewDidLoad方法如下:

              UITabBarController *tc = (UITabBarController *)self.parentViewController;
              NSArray *vcs = tc.viewControllers;
              BOOL tabsInitialized=YES;
              for (UIViewController *vc in vcs)
              {
                if ([vc.tabBarItem.title isEqualToString:@"Not Set"])
                {
                  tabsInitialized = NO;
                  break;
                }
              }
              if (!tabsInitialized)
              {
                int I=1;
                for (UIViewController *vc in vcs)
                {
                  vc.tabBarItem.title = [NSString stringWithFormat:@"Tab %i", i++];
                }
              }
            }
            

            【讨论】:

              【解决方案7】:

              我意识到这个问题在不久前得到了回答,但没有提到直接使用UITabBar 并覆盖其UITabBarDelegate tabBar(:,didSelect item:) 方法的解决方案,而不是让UITabBarController 间接处理选择。

              extension MyListViewController: UITabBarDelegate {
              
                  func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
              
                      // Set some filter based on the selected item or its tag (tag values can be assigned in IB)
                      switch item.tag {
                          // Apply filter to your datasource based on the item.tag
                      }
              
                      // Or if you are using a CoreData NSFetchedResultsController, set its predicate:
                      // resultsController.predicate = makePredicate(item.tag)
                      // resultsController.performFetch()
              
                      tableView.reloadData()
                  }
              }
              

              通过直接覆盖UITabBarDelegate 方法,您可以直接控制选项卡的选择行为。因此,您可以重复使用 UIViewController 的相同实例,而不是 UITabBarController 坚持为每个选项卡创建 UIViewController 的新实例。例如,在didSelect 方法中,您可以对UITableView 中的现有项目列表应用过滤器,而不是像其他解决方案那样在新的UITableView 中创建列表的新实例。

              注意:如果您在代码或 IB 中的视图控制器中使用 UITabBar,UIKit 似乎无法识别它的存在和“重叠”滚动视图(例如 UITableView、@ 987654335@) 不会自动调整他们的contentInset。如果您将UITabBar 的底部锚定到安全区域的底部(它看起来像“浮动”,它自身和屏幕边缘)。

              解决方案(第 1 部分): 专门在 UITabBar 实例上设置顶部约束:首先将标签栏的 底部 边缘锚定到 Superview 和将 top 边缘锚定到 Safe Areabottom 边缘,并将常量设置为 49(截至目前,UITabBar 的标准高度)写作)。然后它在有和没有安全区域边距的设备上看起来都是正确的。

              解决方案(第 2 部分):您需要手动调整 tableView.contentInset / collectionView.contentInset 以确保内容可以在标签栏下滚动。您需要确保最底部的项目仍然可以在底部标签栏上方向上滚动:

              1. 在您的 viewDidLoad() 中禁用自动内容插入调整:

                tableView.contentInsetAdjustmentBehavior = .never
                
              2. 在适当的位置调整UIScrollView.contentInset,添加以下方法并在viewDidLoad() 中调用它,或者在每次视图布局时在viewDidLayoutSubviews() 中调用它。 (如果viewDidLoad() 对你来说太早了,viewWillAppear() 也可能太早了。)

                private func adjustScrollViewInsets() {
                
                    // This snippet only insets the bottom of the table view, but you may need to adjust both top and bottom edges if you also need to accommodate a top navigation bar.
                
                    var contentInset = tableView.contentInset
                    if let windowInsets = view.window ?? UIApplication.shared.keyWindow?.safeAreaInsets {
                        contentInset.bottom = windowInsets.bottom
                    } else {
                        contentInset.bottom = 0
                    }
                    tableView.contentInset = contentInset
                }
                

              【讨论】:

                猜你喜欢
                • 2013-06-04
                • 2020-01-28
                • 2015-09-14
                • 1970-01-01
                • 2016-06-06
                • 1970-01-01
                • 2016-07-23
                • 1970-01-01
                • 2011-12-28
                相关资源
                最近更新 更多