【问题标题】:iOS7 - Setting selectedIndex of UITabBarController breaks touch events along right-hand edge of screen?iOS7 - 设置 UITabBarController 的 selectedIndex 会破坏屏幕右侧边缘的触摸事件?
【发布时间】:2013-10-10 00:30:01
【问题描述】:

我在 iOS7 上遇到了 UITabBarController 的一个奇怪问题,似乎找不到解决方法,所以欢迎任何帮助!

场景:

  • 基于导航的应用在 iPad 上使用横向。
  • 应用由一个主视图和一个作为 UITabBarController 的第二个视图组成。
  • TabBarController 有两个选项卡。
  • 第一个视图有两个按钮 - 每个按钮执行到选项卡栏控制器的 segue 并将不同的选项卡设置为选中状态。 (即 button1 选择第一个选项卡,而 button2 选择第二个选项卡)。
  • 通过在标签栏控制器上调用setSelectedIndex,在prepareForSegue 中设置标签。

结果:

在 iOS 7 上,我发现标签栏控制器中显示的视图无法在视图的右侧边缘注册任何触摸事件!所以在上图的storyboard中,不能点击屏幕右侧的UISwitch。

我什至在视图上附加了一个轻击手势识别器,并用它来记录可以触摸的屏幕区域 - 它似乎记录了最多大约 x=770 点的触摸事件。屏幕的剩余 1/4 是“不可触摸的”!

在转场之后,如果您手动切换到另一个选项卡并再次切换回来,则触摸事件是“固定的”,并且完整视图会再次响应触摸。

这在 iOS 5 / 6 上似乎不是问题。

任何帮助都非常感谢:

  1. 首先是什么导致这种情况发生(iOS7 错误/更改?)
  2. 我还能如何解决这个问题?我试过打电话给setSelectedViewController 以及使用setSelectedIndex,这似乎是一样的。

提前致谢。

【问题讨论】:

  • 您是否尝试过使用 Reveal App 或 Spark Inspector 之类的工具来查看视图层次结构中是否发生了任何奇怪的事情?
  • 我在这里看到了同样的问题。我的猜测是它与框架/边界在方向上没有正确设置有关。

标签: ios7 uitabbarcontroller frame selectedindex


【解决方案1】:

正确答案对我不起作用,因为用户可以改变方向;并且在改变方向时在某些区域仍然无法触摸。

所以我创建了自己的解决方案,我不确定这是正常的解决方案。

@implementation FixedIOS7TabBarController
- (UIView*)findInSubview:(UIView*)view className:(NSString*)className
{
    for(UIView* v in view.subviews){
        if([NSStringFromClass(v.class) isEqualToString:className])
            return v;
        UIView* finded = [self findInSubview:v className:className];
        if(finded)
            return finded;
    }
    return nil;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    UIView* wraperView = [self findInSubview:self.view className:@"UIViewControllerWrapperView"];
    wraperView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
}
@end

非常适合我!

【讨论】:

    【解决方案2】:

    this answer 中所述,

    标签栏控制器设置为包含您的容器视图 视图控制器未调整大小以适应界面 处于横向。在您查看时它的尺寸 控制器显示为 768(宽)x 1024(高)。

    当 TabBarController 最初以纵向模式显示时,我遇到了这个问题。当设备旋转到横向模式时,右侧的视图没有响应。

    该答案中提出的解决方案对我不起作用,因为viewWillAppear: 仅被调用一次。但是,每当视图更改(包括旋转)时都会调用viewDidLayoutSubvews,因此我的解决方案是继承 UITabBarController 并在viewDidLayoutSubvews 中执行解决方法:

    @implementation FixedIOS7TabBarController
    
    - (void)viewDidLayoutSubviews
    {
        // fix for iOS7 bug in UITabBarController
        self.selectedViewController.view.superview.frame = self.view.bounds;
    }
    
    @end
    

    【讨论】:

    • 这肯定表明被授予正确答案的标志。谢谢。
    • 不应该也叫 super 吗?
    • @JimRoepcke:根据 UIViewController 文档,不需要调用 super。
    • IMO viewDidLayoutSubview 和设置超级视图的框架是危险的。如果 Apple 将来会改变某些东西,这可能会导致递归或创建事件的无限循环。
    【解决方案3】:

    在左侧的视图控制器列表中导航到受影响的视图/视图控制器,将视图拖到第一响应者下方,使其与视图控制器的视图解除关联。

    然后转到右侧的布局选项卡,选择所有 4 个锚点和两组调整大小箭头(水平 + 垂直)。

    然后将视图拖回原来的位置(就在视图控制器下方)。

    【讨论】:

      【解决方案4】:

      我最终向开发者技术支持提出了这个问题,它看起来像一个错误。这是我从 Apple 收到的回复:

      标签栏控制器设置为包含您的视图控制器的容器视图未调整大小以考虑界面处于横向。显示视图控制器时的尺寸为 768(宽)x 1024(高)。

      当显示所选标签的视图时,视图层次结构如下所示:

      UIWindow
          /* Navigation Controller */
          UILayoutContainerView
              UINavigationTransitionView
                  UIViewControllerWrapperView
                      /* Tab bar controller */
                      UILayoutContainerView
                          UITransitionView
                              UIViewControllerWrapperView <-- Incorrectly sized.
                                  /* MyViewController */
                                  MyViewController.view
      

      不正确的 UIViewControllerWrapperView 大小不会导致显示问题,因为即使子视图超出其父视图的范围,它们仍会显示。但是,事件路由要严格得多。屏幕右侧四分之一的事件永远不会路由到您的视图控制器的视图,因为命中测试在大小错误的 UIViewControllerWrapperView 处失败,其中事件超出了 UIViewControllerWrapperView 的范围。

      作为一种解决方法,我将 UITabBarController 子类化,并在 viewWillAppear 中添加了以下内容:

      @implementation FixedIOS7TabBarController
      
      - (void)viewWillAppear:(BOOL)animated {
          [super viewWillAppear:animated];
          // Fix the frame of the UIViewControllerWrapperView
          self.selectedViewController.view.superview.frame = self.view.bounds;
      }
      
      @end
      

      希望对其他人有所帮助....

      【讨论】:

      【解决方案5】:

      最终找到解决方法here

      self.view.autoresizesSubviews = YES;
      self.view.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
      

      【讨论】:

      • 我无法让它工作。你把这段代码放到了哪个视图控制器/方法中?
      • 我把它放在根视图控制器中的选项卡栏项目之一,或者特别是展示坏帧/边界问题的那个。
      • 我在 TabController 方法 viewDidLoad 中只放置了第二行,它运行良好。我有奇怪的行为,我的观点也向上和向右移动了 124 点。我更喜欢这个解决方案,因为它比改变超级视图的框架更少干扰。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-05
      • 1970-01-01
      • 1970-01-01
      • 2010-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多