2010-11-19 49 views
3

我遇到了我正在实现的视图的问题。UISwipeGestureRecognizer调用两次

这是一个显示CATiledLayer中的pdf页面的视图。该平铺视图位于UISCrollView中。

我将视图控制为“ZoomingPDFView”苹果示例。我做了一些修改,以便在滚动未启用时识别滑动手势,并在本网站的各种线程和问题中提供建议。那时手势被称为一次。但是,因为我需要分离视图并委托滑动来缓存页面并做一个多功能视图,所以我创建了一个视图控制器来处理滑动手势,并且页面加载方法提高了pdf视图的性能。

现在我已经看到一侧和控制器在另一侧,滑动手势被检测两次,我甚至无法得出问题的线索。

这是控制台输出

2010-11-19 11:45:08.370 ZoomingPDFViewerForIPad[20327:207] initWithFrame and page 
2010-11-19 11:45:08.530 ZoomingPDFViewerForIPad[20327:207] drawPage 
2010-11-19 11:45:08.531 ZoomingPDFViewerForIPad[20327:207] scale: 1.000000 
2010-11-19 11:45:08.531 ZoomingPDFViewerForIPad[20327:207] pdf scale: 1.290062 
2010-11-19 11:45:08.532 ZoomingPDFViewerForIPad[20327:207] pdf initial scale: 1.290062 
2010-11-19 11:45:15.488 ZoomingPDFViewerForIPad[20327:207] left 
2010-11-19 11:45:15.489 ZoomingPDFViewerForIPad[20327:207] left 
2010-11-19 11:45:15.490 ZoomingPDFViewerForIPad[20327:207] initWithFrame and page 
2010-11-19 11:45:15.538 ZoomingPDFViewerForIPad[20327:207] drawPage 
2010-11-19 11:45:15.538 ZoomingPDFViewerForIPad[20327:207] scale: 1.000000 
2010-11-19 11:45:15.539 ZoomingPDFViewerForIPad[20327:207] pdf scale: 1.290062 
2010-11-19 11:45:15.539 ZoomingPDFViewerForIPad[20327:207] pdf initial scale: 1.290062 
2010-11-19 11:45:15.540 ZoomingPDFViewerForIPad[20327:1a07] initWithFrame and page 
2010-11-19 11:45:15.541 ZoomingPDFViewerForIPad[20327:5f07] initWithFrame and page 
2010-11-19 11:45:15.593 ZoomingPDFViewerForIPad[20327:1a07] drawPage 
2010-11-19 11:45:15.594 ZoomingPDFViewerForIPad[20327:1a07] scale: 1.000000 
2010-11-19 11:45:15.594 ZoomingPDFViewerForIPad[20327:1a07] pdf scale: 1.290062 
2010-11-19 11:45:15.595 ZoomingPDFViewerForIPad[20327:1a07] pdf initial scale: 1.290062 
2010-11-19 11:45:15.695 ZoomingPDFViewerForIPad[20327:5f07] drawPage 
2010-11-19 11:45:15.704 ZoomingPDFViewerForIPad[20327:5f07] scale: 1.000000 
2010-11-19 11:45:15.707 ZoomingPDFViewerForIPad[20327:5f07] pdf scale: 1.290062 
2010-11-19 11:45:15.713 ZoomingPDFViewerForIPad[20327:5f07] pdf initial scale: 1.290062 

下面的代码:

#import <UIKit/UIKit.h> 

@class TiledPDFView; 
@protocol PDFScrollViewDelegate; 

@interface PDFScrollView : UIScrollView <UIScrollViewDelegate> { 
// The TiledPDFView that is currently front most 
TiledPDFView *pdfView; 
// The old TiledPDFView that we draw on top of when the zooming stops 
TiledPDFView *oldPDFView; 


// A low res image of the PDF page that is displayed until the TiledPDFView 
// renders its content. 
UIImageView *backgroundImageView; 


id<PDFScrollViewDelegate,NSObject> pdfViewDelegate; 

// current pdf zoom scale 
CGFloat pdfScale; 

CGPDFPageRef page; 
CGPDFDocumentRef pdf; 
CGFloat initialScale; 
TiledPDFView *initialTiledView; 
int currentPage; 
int pageCount; 

UITapGestureRecognizer *doubleTap,*twoFingerDoubleTap; 
UISwipeGestureRecognizer *rightSwipe, *leftSwipe; 



} 

@property (nonatomic,retain) id<PDFScrollViewDelegate> pdfViewDelegate; 
-(id)initWithFrame:(CGRect)rect; 
-(id)initWithFrame:(CGRect)frame andPDFPage:(CGPDFPageRef)aPage; 
-(void)enableGestures; 
-(void)drawPage; 
@end 

@implementation PDFScrollView 
@synthesize pdfViewDelegate; 

…. 

-(void)enableGestures{ 
leftSwipe = [[UISwipeGestureRecognizer alloc ]initWithTarget:self action:@selector(handleRightSwipe:)]; 

leftSwipe.direction = UISwipeGestureRecognizerDirectionRight; 

[self addGestureRecognizer:leftSwipe]; 

//add right swipe 
rightSwipe = [[UISwipeGestureRecognizer alloc ]initWithTarget:self action:@selector(handleLeftSwipe:)]; 
rightSwipe.direction = UISwipeGestureRecognizerDirectionLeft; 
[self addGestureRecognizer:rightSwipe]; 



doubleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleDoubleTap:)]; 
doubleTap.numberOfTapsRequired =2; 
doubleTap.numberOfTouchesRequired =1; 
[self addGestureRecognizer:doubleTap]; 


twoFingerDoubleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(handleTwoFingerDoubleTap:)]; 
twoFingerDoubleTap.numberOfTapsRequired =2; 
twoFingerDoubleTap.numberOfTouchesRequired =2; 
[self addGestureRecognizer:twoFingerDoubleTap]; 


} 

// some more code 
@end 

#import <UIKit/UIKit.h> 
#import "PDFScrollViewDelegate.h" 
@class TiledPDFView; 


@interface ZoomingPDFViewerForIPadViewController : UIViewController <UIScrollViewDelegate,PDFScrollViewDelegate> { 

CGPDFPageRef page; 



CGPDFDocumentRef pdf; 

NSInteger currentPage; 



NSInteger pageCount; 

PDFScrollView *myScrollView; 

PDFScrollView *previousPage; 
PDFScrollView *nextPage; 

} 

-(id)initWithResourcePath:(NSString*)path ; 
-(void)loadNextPage; 
-(void)loadPreviousPage; 
@end 


@implementation ZoomingPDFViewerForIPadViewController 

// some more code 
#pragma mark - 
#pragma mark PDFScrollViewDelegate methods 
/* 
called when user swipes right on the view 
*/ 

-(void)viewDetectedRightSwipe:(PDFScrollView*)pdfScrollView withGesture:(UISwipeGestureRecognizer*)recognizer { 
    NSLog(@"right"); 
if (currentPage>1){ 
    //decreate page counter 
    currentPage--; 


    // release old next page 

    if(nextPage){ 
    [nextPage release]; 
    } 
    // set the actual page as the next one 
    nextPage = [myScrollView retain]; 

    // remove the view from the actual view 
    [myScrollView removeFromSuperview]; 

    // check if the previous page is loaded 
    if(!previousPage) 
    [self loadPreviousPage]; 

    // set the previouse page as the actual page 
    myScrollView = previousPage; 

    myScrollView.pdfViewDelegate = self; 
    //[myScrollView drawPage]; 
    // load a new previous page 
    //[NSThread detachNewThreadSelector:@selector(loadNextPage) toTarget:self withObject:nil]; 
    //[self loadNextPage]; 


} 
} 
/* 
called when user swipes left on the view 
*/ 
-(void)viewDetectedLeftSwipe:(PDFScrollView*)pdfScrollView withGesture:(UISwipeGestureRecognizer*)recognizer{ 
NSLog(@"left"); 
// if the end of the document isn't reached 
if (currentPage<pageCount){ 
    //increment current page 
    currentPage++; 
    // if a previous page has been loaded release it 
    if (previousPage) { 
    [previousPage release]; 
    } 
    // assing the actual view to as a previous page and retain it before it gets release by superview 
    previousPage = [myScrollView retain]; 
    // remove the view from the super view 
    [myScrollView removeFromSuperview]; 

    // if a next page hasn't beeen loaded yet, load it on this thread 
    if (!nextPage) 
    [self loadNextPage]; 

    // assign the next page as the current page 
    myScrollView = nextPage; 

    // put the current page the delegate 
    myScrollView.pdfViewDelegate = self; 

    // add the current page to the super view 
    [[self view] addSubview:myScrollView]; 

    // load a next page. 
    [NSThread detachNewThreadSelector:@selector(loadNextPage) toTarget:self withObject:nil]; 
//[self loadNextPage]; 


} 

} 

/* 
called when the user taps the screen 
*/ 
-(void)viewDetectedTapping:(PDFScrollView*)pdfScrollView withGesture:(UITapGestureRecognizer*)recognizer { 
NSLog(@"tapped"); 
[myScrollView setZoomScale:1.0f animated:YES]; 


} 


-(void)loadNextPage { 
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
CGPDFPageRef aPage = CGPDFDocumentGetPage(pdf, currentPage+1); 
nextPage = [[PDFScrollView alloc] initWithFrame:myScrollView.frame andPDFPage:aPage ]; 
[pool release]; 
} 



-(void)loadPreviousPage { 

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
CGPDFPageRef aPage = CGPDFDocumentGetPage(pdf, currentPage-1); 
previousPage = [[PDFScrollView alloc] initWithFrame:myScrollView.frame andPDFPage:aPage]; 
[pool release]; 
} 
@end 

这是举手投足引起的代码。

-(void)handleRightSwipe:(UIGestureRecognizer*)gesture { 


    if ([pdfViewDelegate respondsToSelector:@selector(viewDetectedRightSwipe:withGesture:)]) { 
     UISwipeGestureRecognizer *swipe = (UISwipeGestureRecognizer*)gesture; 
     [pdfViewDelegate viewDetectedRightSwipe:self withGesture:swipe]; 

    } 




} 
-(void)handleLeftSwipe :(UIGestureRecognizer*)gesture{ 


    if ([pdfViewDelegate respondsToSelector:@selector(viewDetectedLeftSwipe:withGesture:)]) { 
     UISwipeGestureRecognizer *swipe= (UISwipeGestureRecognizer*)gesture; 
     [pdfViewDelegate viewDetectedLeftSwipe:self withGesture:swipe]; 

    } 

} 

预先感谢您的时间

+0

请显示handleRightSwipe和/或handleLeftSwipe的代码。 – Anna 2010-11-19 15:09:31

+0

我刚刚做了一个编辑。谢谢(顺便提一下,很棒的用户名) – Pacu 2010-11-20 19:39:48

回答

1

在iOS上4.x.x有一个bug,导致回调被调用,如果你两次回调里面removeFromSuperview。

您可以设置enabled属性为NO在removeFromSuperview:

- (void)removeFromSuperview 
{ 
    for(UIGestureRecognizer* gestureRecognizer in self.gestureRecognizers) { 
     gestureRecognizer.enabled = NO; 
    } 
    [super removeFromSuperview]; 
} 

- (void)willMoveToSuperview:(UIView *)newSuperview 
{ 
    for(UIGestureRecognizer* gestureRecognizer in self.gestureRecognizers) { 
     gestureRecognizer.enabled = YES; 
    } 
    [super willMoveToSuperview:newSuperview]; 
} 

然而,回调仍会触发,即使它被禁用。 因此,您应该检查回调中启用的属性:

- (void)didSwipeRight:(UISwipeGestureRecognizer *)gestureRecognizer 
{ 
    if (gestureRecognizer.enabled) { 
      //do something useful... 
    } 
} 
1

尝试将它传递给委托之前检查操作的状态属性:

-(void)handleRightSwipe:(UIGestureRecognizer*)gesture { 
    if (gesture.state != UIGestureRecognizerStateEnded) 
     return; //gesture not finished yet 

    if ([pdfViewDelegate respondsToSelector:@selector(viewDetectedRightSwipe:withGesture:)]) { 
     UISwipeGestureRecognizer *swipe = (UISwipeGestureRecognizer*)gesture; 
     [pdfViewDelegate viewDetectedRightSwipe:self withGesture:swipe]; 
    } 
} 

如果这样的作品,做了同样的左滑动。

+0

有些时候有效。看起来手势已结束,然后该方法被触发两次。这出现在我最后的谷歌搜索(具有相同的条款:S)http://stackoverflow.com/questions/4226239/uiswipegesturerecognizer-called-twice/4234640#4234640 – Pacu 2010-11-20 21:42:44

+0

尝试把状态检查在手势处理程序。还要确保手势识别器只添加一次到视图中。是否有可能多次调用enableGestures? – Anna 2010-11-20 22:31:56

-1

当手势被用户“完成”检测到手势时,aBitObvious的答案很好,但这是真正开始深入研究问题的好地方。这里的事情是手势本身被检测到一次,但与它相关的动作被触发两次。我做了一个计时器来跟踪这些呼叫之间的毫秒数,以忽略对该操作的虚假呼叫。

5

@Pacu,

不要使用计时器!

您需要查看手势状态。 UIGestureRecognizer向您发送有关您正在获取的手势的哪部分信息。手势不是一个单一的事件。考虑一个捏手势......它不只发生一次,它开始,改变位置,并可以取消或失败或结束。每当发生这些事情之一时,您的回调就会运行。

只是忽略发生在一起的事件通常会起作用,但是例如,轻扫手势可能会持续比您的时间窗更长的时间。

switch (sender.state) { 
    case UIGestureRecognizerStateBegan: 
     self.dragging = [self objectToRotateOrPinch:sender]; 
     break; 
    case UIGestureRecognizerStateEnded: 
     self.dragging = nil; 
     break; 
    case UIGestureRecognizerStateCancelled: 
     self.dragging = nil; 
     break; 
    case UIGestureRecognizerStateFailed: 
     self.dragging = nil; 
     break; 
    case UIGestureRecognizerStateChanged: 
     // rotate or pinch 
     break; 
    default: 
     break; 
} 

如果所有你关心的是,当一个刷卡已经发生了,你会想才反应过来时,状态== UIGestureRecognizerStateEnded。

+0

我会试试Kenny。谢谢!我不喜欢计时器 – Pacu 2010-12-02 00:40:50

+1

嘿肯尼,我已经试过了,似乎手势识别器只是通知“结束”状态,而不是“之间”状态,如更改,失败,取消。被解雇的是两个“结束”状态。说到“UILongpressGestureRecognizer”,你说的是真的,但似乎并非如此。 – Pacu 2010-12-08 19:28:35

7

我有完全相同的问题,我的猜测是,在执行这条线时,第二个动作射击:

[myScrollView removeFromSuperview]; 

出于某种原因,UISwipeGestureRecognizer火灾时,被删除它附着的观点。没有其他UIGestureRecognizer出现这样做。

我的解决办法是在调用removeFromSuperview前,请关闭所有的手势识别:

for (UIGestureRecognizer *g in myScrollView.gestureRecognizers) { 
    g.enabled = NO; 
    g.delegate = nil; 
} 
[myScrollView removeFromSuperview]; 

这是不理想,但它的伎俩。

+1

我一直在观察这个杰夫,在我的情况下似乎可能,但控制台输出显示,否则。无论如何,我已经尝试了很多事情,以至于我也会为您的解决方案提供一个解决方案。 – Pacu 2010-12-08 19:31:02

+1

我看到使用SDK 4.2的情况完全相同:如果视图从超级视图中移除,则再次刷新火焰!奇怪的。 – Krumelur 2011-03-10 16:12:36

+0

我也证实了这一点。看起来像一个错误。 – Kamchatka 2011-06-13 01:34:13

1

下面的代码是一个简单的解决方法,我认为它不可能有任何不需要的副作用。

- (void) leftSwipe: (UISwipeGestureRecognizer *) recognizer; 
{ 
    if (![recognizer isEnabled]) return;  
    [recognizer setEnabled:NO]; 
    [recognizer performSelector:@selector(setEnabled:) withObject: [NSNumber numberWithBool:YES] afterDelay:0.1]; 
     // your gesture handling code here.... 

我碰到这个问题时,我使用的通知来接受我的手势,直接接收他们交换,但我还没有进一步调查过的问题。州财产对我来说绝对没有帮助 - 记录显示第一次和第二次调用使识别器处于相同状态。

1

我有同样的问题,看来,当您尝试删除视图(手势火灾)发生的问题,因此,改写removeFromSuperview ...这sniplet对我的作品......

- (void)removeFromSuperview 
{ 
    for(UIGestureRecognizer* gesture in [self gestureRecognizers]) 
     [self removeGestureRecognizer:gesture]; 
    [super removeFromSuperview]; 
} 
1

我有完全相同的问题,你也可以发送removeGestureRecognizer:消息到UIView类的类。

-(void)handleLeftSwipe:(UIGestureRecognizer *)gesture 
{ 
    UIView *vw = [gesture view]; 
    [view removeGestureRecognizer:gesture]; 
    [view removeFromSuperview]; 
} 

但是,我仍然不知道为什么从超级视图中删除视图时手势是'触发'的。

干杯,