34

내 응용 프로그램 내에서 스프링 보드 같은 인터페이스를 만들려고합니다. UIScrollView 추가 된 UIButtons 사용하려고합니다. 내가 실행중인 문제는 UIScrollView를 건드리지 않고 단추를 누르는 것입니다. - 밀어 넣기/밀어 넣기를 시도하고 UIScrollView에 등록하지 않은 단추를 누르면 발생하지만, 버튼이 작동합니다. 터치하면 버튼이 클릭/작동합니다.UIButtons가있는 UIScrollview - 스프링 보드를 다시 만드는 방법은 무엇입니까?

버튼이 부모 (수퍼바이저)에게 터치 이벤트를 보내도록하는 속성이나 설정이 있습니까? UIScrollView를 추가하기 전에 단추를 다른 것에 추가해야합니까?

//init scrolling area 
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 480, 480)]; 
scrollView.contentSize = CGSizeMake(480, 1000); 
scrollView.bounces = NO; 
scrollView.delaysContentTouches = NO; 

//create background image 
UIImageView *rowsBackground = [[UIImageView alloc] initWithImage:[self scaleAndRotateImage:[UIImage imageNamed:@"mylongbackground.png"]]]; 
rowsBackground.userInteractionEnabled = YES; 

//create button 
UIButton *btn = [[UIButton buttonWithType:UIButtonTypeCustom] retain]; 
btn.frame = CGRectMake(100, 850, 150, 150); 
btn.bounds = CGRectMake(0, 0, 150.0, 150.0); 
[btn setImage:[self scaleAndRotateImage:[UIImage imageNamed:@"basicbutton.png"]] forState:UIControlStateNormal]; 
[btn addTarget:self action:@selector(buttonClick) forControlEvents:UIControlEventTouchUpInside]; 

//add "stuff" to scrolling area 
[scrollView addSubview:rowsBackground]; 
[scrollView addSubview:btn]; 

//add scrolling area to cocos2d 
//this is just a UIWindow 
[[[Director sharedDirector] openGLView] addSubview:scrollView]; 

//mem-mgmt 
[rowsBackground release]; 
[btn release]; 
[scrollView release]; 
+0

는 '10.4' '멀티 앱 위젯 경험을 다른 데스크탑/홈 스크린 환경을 만들거나 시뮬레이션 앱이 rejected'됩니다 애플 전에 그것을 허용에도 불구하고 있음을 주목해야한다. 일부 신규 사용자가 자체 발판이있는 프로덕션 응용 프로그램을 출시 할 계획이었던 경우를 대비하여. – user

답변

28

UIScrollView이 콘텐츠보기로 전달되는 클릭과 스 와이프 또는 핀치가되는 터치 사이의 차이를 확인하려면 터치를 지연하고 손가락이 이동했는지 확인해야합니다 그 지연. 위의 예에서 delaysContentTouchesNO으로 설정하면이 문제가 발생하지 않습니다. 따라서 스크롤보기는 사용자가 스 와이프 제스처를 수행하는 것으로 판명되면 취소하는 대신 항상 버튼에 터치를 전달합니다. delaysContentTouchesYES으로 설정하십시오.

스크롤 뷰에서 호스팅 할 모든 뷰를 공통 컨텐츠 뷰에 ​​추가하고 해당 뷰를 스크롤 뷰의 하위 뷰로 만 사용하는 것이 좋습니다.

+3

delaysContentTouches를 할 때 발생할 수있는 한 가지 문제점은 버튼이 강조 표시되기 전에 지연이 추가된다는 것입니다. 아래 Roman K의 대답은 지연을 허용하지 않지만 버튼을 누른 후에도 계속 스크롤 할 수 있습니다. – GhostM

+0

구조에 대한 조언은 훌륭하지만 왜 그럴까? 감사. –

1

있는 UIScrollView 이벤트 자체를 많이 처리합니다

여기 내 코드입니다. UIDcrollView 내부의 버튼에 대해 DidEnd 및 hit 테스트를 수동으로 처리해야합니다.

0

또 다른 방법은 다음과 같습니다.
1. 간단한 사용자 정의 UIView
으로 버튼 대체 2. "userInterationEnable = yes;"플래그를 넣습니다. init 메서드
에 3.보기에서 UIResponder 메서드 "touchesEnded"를 재정의하면 여기에 단추처럼 필요한 작업이 트리거 될 수 있습니다.

0

내 경험에 비추어 볼 때 첫 번째 대답은 delaysContentTouchesYES으로 설정하는 것만으로는 문제가 해결되지 않습니다. 버튼은 여전히 ​​스크롤 결과에 추적 결과를 제공하지 않습니다. 세 번째 대답은 간단하고 매우 유용합니다. 감사합니다 sieroaoj!

그러나 세 번째 답변을 사용하려면 delaysContentTouchesYES으로 설정되어야합니다. 그렇지 않으면 메서드 내에서 추적을 위해 touchesEnded 메서드가 호출됩니다. "userInterationEnable = 예;"플래그를 넣어 간단한 사용자 정의 UIView의

  • 에 의해

    1. 대체 드 버튼 : 그러므로 나는하여 문제를 해결할 수 에보기 UIResponder 메서드를 재정에서 init 메소드
    2. 여기에 당신이 행동하면

    네 번째를 트리거 할 수 있습니다 "touchesEnded".

    서브 클래스있는 UIButton : 여기 delaysContentTouches

  • +0

    delaysContentTouches = 기본적으로 YES입니다. – Andy

    1

    YES 확인을 설정하는 것은 당신의 대답이다. (참고 : 각 재정의 시작시 [슈퍼 ....]로 전화하십시오.

    • 속성을 추가하십시오. BOOL 유형 중 하나 (enableToRestore라고 함)
    • 속성을 추가하십시오. 로 awakeFromNib 및 initWithFrame에서
    • (startTouchPosition라고도 함) 형태 CGPoint 중 하나는의 IsEnabled 속성)
    • 재정에 enableToRestore 설정 "touchesBegan : withEvent는" 터치 위치의 시작을 저장합니다.
    • "touchesMoved : withEvent :"를 으로 대체하십시오. 가로가 인지 확인하십시오.
    • YES 인 경우에는 enabled를 NO로 설정하고 을 NO로 선택하십시오.

    샘플 코드 :

    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
    { 
        UITouch *touch = [touches anyObject]; 
    
        [super touchesBegan:touches withEvent:event]; 
        [self setStartTouchPosition:[touch locationInView:self]]; 
    } 
    
    
    // 
    // Helper Function 
    // 
    - (BOOL)isTouchMovingHorizontally:(UITouch *)touch 
    { 
        CGPoint currentTouchPosition = [touch locationInView:self]; 
        BOOL  rValue = NO; 
    
        if (fabsf([self startTouchPosition].x - currentTouchPosition.x) >= 2.0) 
        { 
         rValue = YES; 
        } 
    
        return (rValue); 
    } 
    
    // 
    // This is called when the finger is moved. If the result is a left or right 
    // movement, the button will disable resulting in the UIScrollView being the 
    // next responder. The parrent ScrollView will then re-enable the button 
    // when the finger event is ended of cancelled. 
    // 
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
    { 
        [super touchesMoved:touches withEvent:event]; 
        if ([self isTouchMovingHorizontally:[touches anyObject]]) 
        { 
         [self setEnabled:NO]; 
         [self setSelected:NO]; 
        } 
    } 
    

    이가있는 UIScrollView을 활성화합니다.

    하위 클래스 UIScrollView. (참고 : 각 재정의 시작 .... [슈퍼] 전화

    • 오버라이드는 모두 "touchesEnded : withEvent :". 그리고 "touchesCancelled : withEvent :"재정에서
    • , (모든 하위 뷰를 재설정 자신의 서브 뷰는) 플래그를 사용할 수
    • 참고 :. 범주를 사용하여 UIView의 방법을 추가합니다.

    - (void) restoreAllEnables 
    { 
        NSArray *views = [self subviews]; 
    
        for (UIView *aView in views) 
        { 
         if ([aView respondsToSelector:@selector(restoreEnable)]) 
         { 
          [aView restoreEnable]; 
         } 
        } 
    } 
    
    - (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 
    { 
        [super touchesEnded:touches withEvent:event]; 
        [self restoreAllEnables]; 
    } 
    
    - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event 
    { 
        [super touchesEnded:touches withEvent:event]; 
        [self restoreAllEnables]; 
    } 
    
    • 범주에서 :

    .

    -(void) restoreEnable 
    { 
        NSArray *views = [self subviews]; 
    
        if ([self respondsToSelector:@selector(enableToRestore)]) 
        { 
         [self setEnabled:[self enableToRestore]]; 
        } 
    
        for (UIView *aView in views) 
        { 
         if ([aView respondsToSelector:@selector(restoreEnable)]) 
         { 
          [aView restoreEnable]; 
         } 
        } 
    } 
    

    편집 참고 : 나는 일에 3 대답도 없었어. 마찬가지로 : setDelaysContentTouches : NO (보기 컨트롤러 또는 다른 곳에서 설정)는 응답 4에서 최상의 결과를 얻을 수 있도록 설정됩니다. 이렇게하면 단추에 매우 빠르게 응답 할 수 있습니다. setDelaysContentTouches : YES를 설정하면 버튼에 대한 응답 시간에 심각한 영향 (150ms)이 가해지며 가볍고 빠르게 감당할 수 없습니다.

    5

    저는 UIScrollView에있는 많은 버튼과 비슷한 버튼을 스크롤하고 싶습니다. 처음에는 UIScrollView와 UIButton을 하위 클래스로 만들었습니다. 그러나, 나는 서브 클래 싱 된 UIScrollView가 touchesEnded 이벤트를받지 못했기 때문에 서브 클래스 UIButton으로 바꿨다. 나를 위해 일한

    
    @interface MyPhotoButton : UIButton { 
    } 
    
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event; 
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event; 
    - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event; 
    @end 
    
    
    @implementation MyPhotoButton 
    
    - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { 
        [super touchesMoved:touches withEvent:event]; 
        [self setEnabled:NO]; 
        [self setSelected:NO]; 
    } 
    
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { 
        [super touchesEnded:touches withEvent:event]; 
        [self setEnabled:YES]; 
    } 
    
    - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { 
        [super touchesCancelled:touches withEvent:event]; 
        [self setEnabled:YES]; 
    } 
    
    @end 
    
    +0

    이 솔루션은 나를 위해 완벽하게 작동했습니다. – GroovyCarrot

    44

    솔루션 포함 :

    1. YESUIScrollViewcanCancelContentTouches 설정.
    2. UIScrollView을 확장하는 것은 viewUIButtonYES를 돌려 touchesShouldCancelInContentView:(UIView *)view를 오버라이드 (override)합니다. .

    그 메시지를 수신 할 전망을 가지고, NO을 볼 수 더 터치 메시지를 취소 문서에 touchesShouldCancelInContentView 반환 "YES을 계속 따르면 기본값은 뷰가 UIControl 객체가 아닌 경우 값이 YES입니다 반환, 그렇지 않으면 NO을 반환 . "

    UIButtonUIControl이므로 canCancelContentTouches을 적용하면 스크롤이 가능해집니다.

    +8

    대단히 감사합니다! 명확히하기 위해, 이것은 delaysContentTouches = NO 일 때 가장 잘 작동합니다. – Schrockwell

    +7

    이것은 갈 길입니다! (적어도 iOS 4 이상) 나는 다음과 같이 오버라이드하는 것이 가장 다재다는 것을 알았습니다 : '- (BOOL) touchesShouldCancelInContentView : (UIView *) 뷰 {return! [view isKindOfClass : [UISlider class]]; }' –

    +0

    iOS에서 여전히 완벽하게 작동합니다. 7. 감사합니다. – RyanG