2009-09-07 2 views
2

NIB 파일에서로드하는 대신 프로그래밍 방식으로 뷰를 만드는 UIViewController 하위 클래스를 작성했습니다.내보기에 대한 응답 체인에 내 UIViewController가없는 이유는 무엇입니까?

그것은 간단한 loadView 방법이 있습니다

- (void)loadView 
{ 
    UIScrollView *mainScrollView = 
     [[UIScrollView alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 
    self.view = mainScrollView; 
    [mainScrollView release]; 
} 

을 ... 설명하는대로 그때, viewDidLoad 내 초기화의 대부분을한다. 그것은 모두 작동하며, 내 사용자 정의보기로 스크롤보기를 볼 수 있습니다.

UINavigationBar 워크 플로의 일부이기 때문에 뷰를 소유하려면 UIViewController가 필요합니다. 컨트롤러 객체를 가지고 있기 때문에 나는 컨트롤러 객체를 사용하고 싶습니다.

문제는 내 View Controller가 응답 체인에없는 것 같습니다. touchesBegan:withEvent:은 내가 루트 컨트롤러 뷰 또는 서브 뷰에 정의하면 호출되지만 뷰 컨트롤러에있는 경우에는 호출되지 않습니다.

Apple 이벤트 처리 설명서에는 view controller should be in the responder chain이 나와 있습니다. UIViewController 설명서는 위에서 수행 한 것처럼 self.view 속성에 루트 뷰를 할당하는 것 이상의 추가 단계에 대해서는 아무 것도 말하지 않습니다. UIResponder 문서에서는 UIView에 컨트롤러가 있는지 여부와 이벤트를 전달해야 하는지를 알아야한다고 주장합니다. UIScrollView 설명서에는 아무런 언급이 없습니다.

행운이없는 모든 뷰와 하위 뷰에 대해 다양한 설정으로 userInteractionEnabled:을 실험했습니다.

무엇이 누락 되었습니까?

+0

내가 있기 때문에 루트 뷰가있는 UIScrollView를 제외하고 어떤 경우, 뷰 컨트롤러가 리스폰 더 체인에 있음을 배웠다. UIScrollView가 깨졌습니까? – EricB

+0

이 답변은 도움이됩니다 : http://stackoverflow.com/a/7808238/790198 – Nianliang

답변

9

EricB, 터치는 처리되지 않은 경우에만 응답 체인에 보내집니다. UIScrollView는 분명히 모든 터치 이벤트를 처리하므로 nextResponder에 아무 것도 보내지 않습니다. 나에게 완벽 해.

실제로 원하는 것은 터치 이벤트가 UIScrollView의 스크롤 논리에 의해 처리되기 전에 터치 이벤트를 "필터링"하는 것입니다. 그러나 응답자 체인은 처리되기 전에 이벤트를 가로채는 것을 허용하지 않기 때문에이 작업에 대한 잘못된 도구라는 점에 유의하십시오.

아마 가장 좋은 해결책은 [super touchesXxx]을 호출하기 전에 UIScrollView를 하위 클래스로 만들고 터치 메서드 (touchesBegan 등)를 재정의 한 다음 대리자에게 수동으로 이벤트를 보내는 것입니다.

+0

UIScrollView는이 작업을 전혀 수행하지 않으며 결코 수행하지 않습니다. 그것은 * 일부 이벤트를 처리하고 나머지는 콘텐츠보기 내의 UIView로 전달합니다. IMHO이 버그는 Apple에서 수정하지 않기로 결정한 버그이며 정답으로 표시해서는 안됩니다. – Adam

0

UIScrollView는 기본적으로 콘텐츠 접촉을 지연합니다. 터치를 통과 할 수 있도록 -delaysContentTouches를 보았습니까?

+0

그들은보기 컨트롤러가 아닌 응답 체인에 다른보기로 잘 전달합니다. – EricB

3

UIScrollView에는 많은 버그와 해결 방법이 있으며 버그에 대한 해결 방법의 버그가 있다고 생각합니다.

UIScrollView를 서브 클래 싱하는 것은 일반적으로 장기적으로 나쁜 생각입니다. 다른 방법으로는 해결할 수없는 다른 이유로 서브 클래스를 만들어야하는 경우가 종종 있습니다. 따라서 다시 사용하려는 경우 코드, 절대적으로해야 할 때까지 하위 클래스를 만들지 마십시오.

가장 간단한 해결책 콘텐츠 뷰를 일관되게 작은 UIView 하위 클래스로 만드는 것으로 나타났습니다. 콘텐츠 뷰 자체가 변경되지 않도록 UIScrollView에서 필요하다는 것을 염두에 두십시오 (예 : 확대/축소를 사용하면 Apple에 버그가 있음). 기존 스크롤보기의 콘텐츠보기를 변경할 때 사용하는 iOS 6 이상), 사소한 것으로 유지하고 하위보기로 사용자 정의보기를 넣는 것이 좋습니다.

NB : 여러 출하 된 앱에서 항상 유용했습니다. 문제가 있으면 아직 보지 못했습니다. 아직까지 실행되지 않은 미묘한 문제가 없다면, 애플이이 간단한 변화를 스스로 구현하지 않는 이유는 모르겠다.

사용법 :

/** 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 
관련 문제