Pergunta

Estou tendo problemas com uma visão que estou implementando.

É uma visão que mostra uma página em PDF em um CatiledLayer. Essa visão de ladrilhos está dentro de um UIScrollView.

Eu tinha a exibição controlando -se como o exemplo da Apple "ZoomingpdfView". Fiz algumas modificações para que ele reconhecesse gestos de deslocamento quando a rolagem não estiver ativada e conselhos em vários tópicos e perguntas neste site. Naquela época, os gestos eram chamados uma vez. Mas, como eu precisava dissociar a visualização e delegar o deslizamento para armazenar em cache as páginas e fazer uma exibição versátil, criei um controlador de exibição para lidar com os gestos de deslocamento e os métodos de carregamento da página aumentam o desempenho da exibição em PDF.

Agora que tenho a vista de um lado e o controlador do outro lado, os gestos deslizantes são detectados duas vezes e não consigo ter uma pista do problema.

Esta é a saída do console

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

Aqui está o código:

#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

Este é o código que os gestos desencadeiam.

-(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];

    }

}

Agradeço antecipadamente pelo seu tempo

Foi útil?

Solução

No iOS 4.xx, há um bug, o que fez com que o retorno de chamada fosse chamado duas vezes se você remover o retorno de chamada do intervalo.

Você pode definir a propriedade ativada como não em RemofFromSuperView:

- (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];
}

No entanto, o retorno de chamada ainda disparará, mesmo que esteja desativado. Portanto, você deve verificar a propriedade ativada no retorno de chamada:

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

Outras dicas

Eu tive exatamente o mesmo problema e meu palpite é que a segunda ação disparada quando essa linha foi executada:

[myScrollView removeFromSuperview];

Por alguma razão, o UiswipeGestureRecognizer dispara quando a visualização é a remoção é removida. Nenhum outro UigestureRecognizer parece fazer isso.

Minha solução foi desativar todos os reconhecedores de gestos antes de ligar para remover o Remofruperview:

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

Não é o ideal, mas fez o truque.

@Pacu,

Não use um cronômetro!

Você precisa estar olhando para o estado do gesto. O UigestureRecognizer envia informações sobre qual parte do gesto você está recebendo. Os gestos não são um único evento. Pense em um gesto de pitada ... ele não acontece apenas uma vez, começa, muda de posição e pode ser cancelado ou falhar ou terminar. Cada vez que uma dessas coisas acontece, seu retorno de chamada é executado.

Apenas ignorar os eventos que acontecem juntos geralmente funcionam, mas, por exemplo, um gesto de furto pode durar mais tempo que a janela do tempo.

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;
}

Se tudo o que você se preocupa é quando um toque ocorreu, você deve reagir apenas quando o estado == UigestureRecognizertende.

Tente verificar a propriedade do estado do gesto antes de passá -lo para o delegado:

-(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];
    }
}

Se isso funcionar, faça o mesmo com o toque esquerdo.

O código a seguir é uma solução alternativa simples, é improvável que tenha efeitos colaterais indesejados.

- (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....

Me deparei com esse problema quando mudei de usar as notificações para receber meus gestos para recebê -los diretamente, mas não procurei mais adiante o problema. A propriedade do estado definitivamente não ajudou em mim - o registro mostrou as primeiras e as segundas chamadas, desde que o reconheceu no mesmo estado.

Eu tive o mesmo problema, parece que o problema ocorre quando você tenta remover a visualização (incêndios em gestos), então, reescreva removefromsuperview ... Este franco -atirador funciona para mim ...

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

Eu tinha exatamente o mesmo problema e você também poderia enviar removeGestureRecognizer: Mensagem para o tipo de classe UIView.

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

No entanto, ainda não sei por que o gesto é "acionado" quando a visualização está sendo removida da supervisão.

Saúde,

A resposta de Abitobvious é boa quando o gesto é detectado, pois está sendo "feito" pelo usuário, mas é realmente um bom lugar para começar a cavar o problema. O problema aqui é que o próprio gesto é detectado uma vez, mas a ação associada a ele é disparada duas vezes. Fiz um cronômetro para acompanhar quantos milissegundos estavam entre essas chamadas para ignorar chamadas falsas para a ação.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top