Objective c UISweepGestureRecognitor调用了两次
我在实现一个视图时遇到了问题 这是一个在CATiledLayer中显示pdf页面的视图。该平铺视图位于UISCrollView中 我将视图控制为“ZoomingPDFView”苹果示例。我做了一些修改,以便它能够识别未启用滚动时的滑动手势,以及该站点上各种线程和问题中的建议。当时,这些手势被称为一次。但是,当我需要分离视图并将滑动委托给缓存页面和执行多功能视图时,我创建了一个视图控制器来处理滑动手势,页面加载方法提高了pdf视图的性能 现在我在一边有了视图,在另一边有了控制器,滑动手势被检测到两次,我甚至连问题的线索都找不到 这是控制台输出Objective c UISweepGestureRecognitor调用了两次,objective-c,ios4,uigesturerecognizer,Objective C,Ios4,Uigesturerecognizer,我在实现一个视图时遇到了问题 这是一个在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 (gesture.state != UIGestureRecognizerStateEnded)
return; //gesture not finished yet
if ([pdfViewDelegate respondsToSelector:@selector(viewDetectedRightSwipe:withGesture:)]) {
UISwipeGestureRecognizer *swipe = (UISwipeGestureRecognizer*)gesture;
[pdfViewDelegate viewDetectedRightSwipe:self withGesture:swipe];
}
}
如果可以的话,用左扫也可以。当用户检测到手势正在“完成”时,AbitoBevious的回答是好的,但它确实是开始深入研究问题的好地方。这里的问题是,手势本身被检测到一次,但与之相关的动作被触发两次。我做了一个计时器来跟踪这些调用之间的毫秒数,以忽略对操作的假调用。@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;
}
如果您关心的只是刷卡发生的时间,那么您只希望在state==UIGestureRecognitizerStateEnded时做出反应。我遇到了完全相同的问题,我猜第二个操作是在执行此行时触发的:
[myScrollView removeFromSuperview];
由于某些原因,当它所附加到的视图被删除时,UISweepGestureRecognizer会触发。似乎没有其他UIgestureRecognitor执行此操作
我的解决方案是在调用removeFromSuperview之前禁用所有手势识别器:
for (UIGestureRecognizer *g in myScrollView.gestureRecognizers) {
g.enabled = NO;
g.delegate = nil;
}
[myScrollView 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) 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....
当我从使用通知接收手势切换到直接接收手势时,我遇到了这个问题,但我没有进一步研究这个问题。state属性对我毫无帮助-日志显示识别器在同一状态下提供的第一次和第二次调用。我也有同样的问题,似乎在尝试删除视图(手势触发)时出现了问题,因此,重写removeFromSuperview。。。这个小剪适合我
- (void)removeFromSuperview
{
for(UIGestureRecognizer* gesture in [self gestureRecognizers])
[self removeGestureRecognizer:gesture];
[super removeFromSuperview];
}
我遇到了完全相同的问题,您还可以向UIView类发送
RemovegestureRecognitizer:
消息
-(void)handleLeftSwipe:(UIGestureRecognizer *)gesture
{
UIView *vw = [gesture view];
[view removeGestureRecognizer:gesture];
[view removeFromSuperview];
}
但是,我仍然不知道当视图从superview中删除时,为什么会“触发”该手势
干杯,在iOS 4.x.x上有一个bug,如果您在回调中从SuperView中移除,则会导致回调调用两次 您可以在removeFromSuperview中将enabled属性设置为NO:
for (UIGestureRecognizer *g in myScrollView.gestureRecognizers) {
g.enabled = NO;
g.delegate = nil;
}
[myScrollView 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];
}
但是,即使已禁用,回调仍将启动。
因此,您应该在回调中检查enabled属性:
- (void)didSwipeRight:(UISwipeGestureRecognizer *)gestureRecognizer
{
if (gestureRecognizer.enabled) {
//do something useful...
}
}
请显示HandleLightSwipe和/或HandleLeftsSwipe的代码。我刚刚做了编辑。谢谢(顺便说一句,非常棒的用户名)曾经奏效过。该手势似乎已结束,然后该方法被触发两次。这在我上一次谷歌搜索中出现(使用相同的术语:S),请尝试将状态检查放入手势处理程序中。另外,请确保仅将手势识别器添加到视图中一次。有没有可能启用手势被多次调用?我要试试肯尼。谢谢我也不喜欢计时器嘿,肯尼,我已经试过了,而且手势识别器似乎只是通知“结束”状态,而不是“中间”状态,如更改、失败、取消。被解雇的是两个“结束”状态。您所说的“UILongpressGestureRecognizer”是正确的,但事实似乎并非如此。我一直在观察这一点,Jeff,在我的情况下,这似乎是可能的,但控制台输出显示了其他情况。不管怎样,我已经尝试了很多方法,我也将尝试一下您的解决方法。我在使用SDK 4.2时看到了完全相同的情况:如果视图从superview中删除,将再次触发滑动!奇怪,我也证实了这一点。看起来像一个bug。这个bug在iOS 4.3而不是5.0上表现出来。不过,你的解决方案在4.3上不起作用。这个bug仍然存在于iOS 12中!英雄联盟不错的解决方案,顺便说一下!:)