为什么我的UIViewController不在响应链中来查看它?

时间:2009-09-07 21:17:03

标签: iphone objective-c uikit uiviewcontroller uiscrollview

我编写了一个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:的各种设置,没有运气。

我错过了什么?

3 个答案:

答案 0 :(得分:9)

EricB,只有在没有处理的情况下才会向响应者链发送触摸。 UIScrollView显然处理所有触摸事件,因此它不向它发送任何东西的nextResponder。对我来说很有意义。

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

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

答案 1 :(得分:4)

我认为问题在于UIScrollView有很多错误,并且有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

答案 2 :(得分:0)

UIScrollView默认会延迟内容触摸;你看过-delaysContentTouches以确保触摸将通过。