为啥我的 UIViewController 不在其视图的响应者链中?

Posted

技术标签:

【中文标题】为啥我的 UIViewController 不在其视图的响应者链中?【英文标题】:Why isn't my UIViewController in the responder chain for its view?为什么我的 UIViewController 不在其视图的响应者链中? 【发布时间】:2009-09-07 21:17:02 【问题描述】:

我编写了 UIViewController 的子类,它以编程方式创建视图,而不是从 NIB 文件中加载它。

它有一个简单的loadView 方法:

- (void)loadView

    UIScrollView *mainScrollView =
        [[UIScrollView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
    self.view = mainScrollView;
    [mainScrollView release];

...然后我在viewDidLoad 中进行大部分初始化,如文档所述。一切正常,我可以看到包含自定义视图的滚动视图。

我需要一个 UIViewController 来拥有视图,因为它是 UINavigationBar 工作流程的一部分。因为我有一个控制器对象,所以我宁愿它做控制器的事情。

那么,问题是我的视图控制器似乎不在响应者链中。如果我在根视图或子视图中定义touchesBegan:withEvent:,则会调用它,但如果它在视图控制器本身中则不会。

Apple 事件处理文档巧妙地提到了view controller should be in the responder chain。 UIViewController 文档没有说明除了将根视图分配给 self.view 属性之外所需的额外步骤,正如我在上面所做的那样。 UIResponder 文档声称 UIView 应该确定它是否具有控制器并将事件传递给它。 UIScrollView 文档什么也没说。

我还为所有视图和子视图尝试了userInteractionEnabled: 的各种设置,但没有成功。

我错过了什么?

【问题讨论】:

我从那以后了解到,如果根视图是 UIScrollView 以外的任何东西,则视图控制器位于响应者链中。 UIScrollView 坏了吗? 这个答案很有帮助:***.com/a/7808238/790198 【参考方案1】:

EricB,只有在没有被处理的情况下,触摸才会被发送到响应者链中。 UIScrollView 显然处理了所有的触摸事件,所以它不会向它的 nextResponder 发送任何内容。对我来说很有意义。

你真正想要的是在它们被 UIScrollView 的滚动逻辑处理之前“过滤”触摸事件。但请注意,响应者链对于这项工作来说是一个错误的工具,正是因为它不允许在事件被处理之前拦截它们。

在您的情况下,最好的解决方案可能是继承 UIScrollView,覆盖触摸方法(touchesBegan 等)并在调用 [super touchesXxx] 之前手动将事件发送给委托。

【讨论】:

除了 UIScrollView 根本不这样做,而且从来没有。它处理 一些 事件,并将其余事件传递给其内容视图中的 UIView。恕我直言,这是 Apple 决定不修复的错误,不应将其标记为正确答案。【参考方案2】:

我认为问题在于 UIScrollView 有很多 bug,以及 bug 的解决方法,以及 bug 的解决方法中的 bug :)。

从长远来看,子类化 UIScrollView 通常是一个坏主意,这使事情变得复杂 - 您经常不得不将其子类化,因为其他原因无法以任何其他方式解决,所以如果您想重用您的代码, 尽量不要继承它,直到你绝对必须这样做。

我发现始终如一的最简单解决方案是让您的内容视图成为一个微小的 UIView 子类 - 请记住 UIScrollView 要求您的内容视图本身永远不会改变(例如,如果您启用缩放 - Apple 有一些错误高达至少 ios 6 会在您更改现有滚动视图的内容视图时启动),因此最好保持简单,并将您的自定义视图作为子视图放入其中。

注意:在多个已发布的应用程序上,这一直对我有用。如果有问题,我还没有看到。我不知道为什么 Apple 不自己实现这个简单的更改,除非它有一个我还没有遇到的微妙问题!

用法:

/** Inside your UIViewController, wherever you set the root content view
of your UIScrollView, you have to also tell the custom class "I am the nextResponder!"
*/
-(void)viewDidLoad

    self.scrollView.contentSize = self.viewEmbeddedInScrollview.frame.size;
    self.viewEmbeddedInScrollview.nextResponderHeyAppleWhyDidYouStealThis = self;

接口文件+类文件:

#import <UIKit/UIKit.h>

@interface UIViewThatNeverLosesItsNextResponder : UIView

@property(nonatomic,retain) UIResponder* nextResponderHeyAppleWhyDidYouStealThis;

@end



#import "UIViewThatNeverLosesItsNextResponder.h"

@implementation UIViewThatNeverLosesItsNextResponder

- (id)initWithFrame:(CGRect)frame

    self = [super initWithFrame:frame];
    if (self) 
        // Initialization code
    
    return self;


@synthesize nextResponderHeyAppleWhyDidYouStealThis;

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

    [nextResponderHeyAppleWhyDidYouStealThis touchesBegan:touches withEvent:event];


-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event

    [nextResponderHeyAppleWhyDidYouStealThis touchesCancelled:touches withEvent:event];


-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

    [nextResponderHeyAppleWhyDidYouStealThis touchesEnded:touches withEvent:event];


-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

    [nextResponderHeyAppleWhyDidYouStealThis touchesMoved:touches withEvent:event];


@end

【讨论】:

【参考方案3】:

UIScrollView 默认会延迟内容触摸;您是否查看过 -delaysContentTouches 以确保触摸会通过。

【讨论】:

它们可以很好地传递给响应者链上的其他视图,而不是视图控制器。

以上是关于为啥我的 UIViewController 不在其视图的响应者链中?的主要内容,如果未能解决你的问题,请参考以下文章

尝试在其视图不在窗口层次结构中的 UIViewController 上呈现 UIViewController

尝试在其视图不在窗口层次结构中的 UIViewController 上呈现 UIViewController

尝试在其视图不在窗口层次结构中的 UIViewController 上呈现 UIViewController

尝试在其视图不在窗口层次结构中的 UIViewController 上呈现 UIViewController

为啥 maven 不在我的 jar 中包含 JSP 文件?

为啥我的 UIButton 不在我认为应该在的位置?