Desplazamiento con dos dedos con un UIScrollView


Tengo una aplicación donde mi vista principal acepta touchesBegan y touchesMoved, y por lo tanto acepta toques con un solo dedo y arrastra. Quiero implementar un UIScrollView, y lo tengo funcionando, pero anula los drags, y por lo tanto mi contentView nunca los recibe. Me gustaría implementar un UIScrollview, donde un arrastre de dos dedos indica un desplazamiento, y un evento de arrastre de un dedo se pasa a mi vista de contenido, por lo que funciona normalmente. Necesito crear mi propia subclase de UIScrollView?

Aquí está mi código desde mi appDelegate donde implemento el UIScrollView.

@implementation MusicGridAppDelegate

@synthesize window;
@synthesize viewController;
@synthesize scrollView;


- (void)applicationDidFinishLaunching:(UIApplication *)application {    

    // Override point for customization after app launch    
    //[application setStatusBarHidden:YES animated:NO];
    //[window addSubview:viewController.view];

    scrollView.contentSize = CGSizeMake(720, 480);
    scrollView.showsHorizontalScrollIndicator = YES;
    scrollView.showsVerticalScrollIndicator = YES;
    scrollView.delegate = self;
    [scrollView addSubview:viewController.view];
    [window makeKeyAndVisible];
}


- (void)dealloc {
    [viewController release];
    [scrollView release];
    [window release];
    [super dealloc];
}
Author: Srikar Appalaraju, 2009-04-24

14 answers

Necesitas subclase UIScrollView (¡por supuesto!). Entonces necesitas:

  • Crea eventos con un solo dedo para ir a tu vista de contenido (fácil), y

  • Haga que los eventos de dos dedos se desplacen en la vista de desplazamiento (puede ser fácil, puede ser difícil, puede ser imposible).

La sugerencia de Patrick generalmente está bien: deje que su subclase UIScrollView sepa sobre su vista de contenido, luego, en contacto, los controladores de eventos comprueban el número de dedos y reenvían el evento en consecuencia. Sólo sé asegúrese de que (1) los eventos que envía a la vista de contenido no vuelven a UIScrollView a través de la cadena de respuesta (es decir, asegúrese de manejarlos todos), (2) respete el flujo habitual de eventos táctiles (es decir, touchesBegan, que algún número de {touchesBegan, touchesMoved, touchesEnded}, terminado con touchesEnded o touchesCancelled), especialmente cuando se trata de UIScrollView. #2 puede ser complicado.

Si decide que el evento es para UIScrollView, otro truco es hacer que UIScrollView crea que su el gesto de dos dedos es en realidad un gesto de un dedo (porque UIScrollView no se puede desplazar con dos dedos). Intente pasar solo los datos de un dedo a super (filtrando el argumento (NSSet *)touches - tenga en cuenta que solo contiene los toques modificados - e ignorando los eventos para el dedo equivocado por completo).

Si eso no funciona, estás en problemas. Teóricamente puede intentar crear toques artificiales para alimentar a UIScrollView creando una clase que se vea similar a UITouch. Subyacente C el código no comprueba los tipos, por lo que tal vez la conversión (YourTouch *) en (UITouch *) funcionará, y podrá engañar a UIScrollView para que maneje los toques que realmente no sucedieron.

Probablemente quieras leer mi artículo sobre trucos avanzados de UIScrollView (y ver algún código de ejemplo de UIScrollView totalmente no relacionado).

Por supuesto, si no puede hacer que funcione, siempre hay una opción de controlar el movimiento de UIScrollView manualmente o usar un vista de desplazamiento escrita a medida. Hay clase TTScrollView en la biblioteca Three20 ; no se siente bien para el usuario, pero se siente bien para el programador.

 10
Author: Andrey Tarantsov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-10 06:02:20

En SDK 3.2 el manejo táctil para UIScrollView se maneja usando reconocedores de gestos.

Si desea hacer una panorámica de dos dedos en lugar de la panorámica predeterminada de un solo dedo, puede usar el siguiente código:

for (UIGestureRecognizer *gestureRecognizer in scrollView.gestureRecognizers) {     
    if ([gestureRecognizer  isKindOfClass:[UIPanGestureRecognizer class]]) {
        UIPanGestureRecognizer *panGR = (UIPanGestureRecognizer *) gestureRecognizer;
        panGR.minimumNumberOfTouches = 2;               
    }
}
 63
Author: Kenshi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-05-15 11:06:47

Para iOS 5+, establecer esta propiedad tiene el mismo efecto que la respuesta de Mike Laurence:

self.scrollView.panGestureRecognizer.minimumNumberOfTouches = 2;

El arrastre de un dedo es ignorado por panGestureRecognizer y, por lo tanto, el evento de arrastre de un dedo se pasa a la vista de contenido.

 33
Author: Guto Araujo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-04 12:53:22

En iOS 3.2+ ahora puede lograr el desplazamiento de dos dedos con bastante facilidad. Simplemente agregue un reconocedor de gestos de panorámica a la vista de desplazamiento y establezca su maximumNumberOfTouches en 1. Reclamará todos los pergaminos de un solo dedo, pero permitirá que más de 2 pergaminos pasen la cadena al reconocedor de gestos de desplazamiento integrado de la vista de desplazamiento (y, por lo tanto, permitirá un comportamiento de desplazamiento normal).

UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(recognizePan:)];
panGestureRecognizer.maximumNumberOfTouches = 1;
[scrollView addGestureRecognizer:panGestureRecognizer];
[panGestureRecognizer release];
 14
Author: Mike Laurence,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-09-25 05:08:06

Estas respuestas son un desastre ya que solo puede encontrar la respuesta correcta leyendo todas las otras respuestas y los comentarios (la respuesta más cercana obtuvo la pregunta al revés). La respuesta aceptada es demasiado vaga para ser útil, y sugiere un método diferente.

Sintetizando, esto funciona

    // makes it so that only two finger scrolls go
    for (id gestureRecognizer in self.gestureRecognizers) {     
        if ([gestureRecognizer  isKindOfClass:[UIPanGestureRecognizer class]])
        {
            UIPanGestureRecognizer *panGR = gestureRecognizer;
            panGR.minimumNumberOfTouches = 2;              
            panGR.maximumNumberOfTouches = 2;
        }
    }   

Esto requiere dos dedos para un pergamino. He hecho esto en una subclase, pero si no, simplemente reemplace self.gestureRecognizers con myScrollView.gestureRecognizers y estará listo.

Lo único que agregué es usar id para evitar un reparto feo:)

Esto funciona, pero puede ser bastante complicado si quieres que tu UIScrollView haga zoom también... los gestos no funcionan correctamente, ya que pellizcar para hacer zoom y desplazarse luchan contra él. Actualizaré esto si encuentro una respuesta adecuada.

 8
Author: Dan Rosenstark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-11-07 07:18:51

Logramos implementar una funcionalidad similar en nuestra aplicación de dibujo para iPhone mediante la subclase UIScrollView y el filtrado de eventos en función del número de toques de manera simple y grosera:

//OCRScroller.h
@interface OCRUIScrollView: UIScrollView
{
    double pass2scroller;
}
@end

//OCRScroller.mm
@implementation OCRUIScrollView
- (id)initWithFrame:(CGRect)aRect {
    pass2scroller = 0;
    UIScrollView* newv = [super initWithFrame:aRect];
    return newv;
}
- (void)setupPassOnEvent:(UIEvent *)event {
    int touch_cnt = [[event allTouches] count];
    if(touch_cnt<=1){
        pass2scroller = 0;
    }else{
        double timems = double(CACurrentMediaTime()*1000);
        pass2scroller = timems+200;
    }
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self setupPassOnEvent:event];
    [super touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    [self setupPassOnEvent:event];
    [super touchesMoved:touches withEvent:event];   
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    pass2scroller = 0;
    [super touchesEnded:touches withEvent:event];
}


- (BOOL)touchesShouldBegin:(NSSet *)touches withEvent:(UIEvent *)event inContentView:(UIView *)view
{
    return YES;
}

- (BOOL)touchesShouldCancelInContentView:(UIView *)view
{
    double timems = double(CACurrentMediaTime()*1000);
    if (pass2scroller == 0 || timems> pass2scroller){
        return NO;
    }
    return YES;
}
@end

ScrollView configurado de la siguiente manera:

scroll_view = [[OCRUIScrollView alloc] initWithFrame:rect];
scroll_view.contentSize = img_size;
scroll_view.contentOffset = CGPointMake(0,0);
scroll_view.canCancelContentTouches = YES;
scroll_view.delaysContentTouches = NO;
scroll_view.scrollEnabled = YES;
scroll_view.bounces = NO;
scroll_view.bouncesZoom = YES;
scroll_view.maximumZoomScale = 10.0f;
scroll_view.minimumZoomScale = 0.1f;
scroll_view.delegate = self;
self.view = scroll_view;

El simple toque no hace nada (puede manejarlo de la manera que necesita), toque con dos dedos scrolls/zooms ver como se espera. no se utiliza gestureRecognizer, por lo que funciona desde iOS 3.1

 2
Author: IPv6,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-10 09:29:36

Tengo una mejora adicional al código anterior. El problema era, que incluso después de establecer setCanCancelContentTouches:NO Tenemos el problema, que un gesto de zoom se interrumpirá con el contenido. No cancelará el toque de contenido, pero permitirá hacer zoom mientras tanto. PARA evitar esto, bloqueo el zoom configurando minimumZoomScale y maximumZoomScale a los mismos valores cada vez que se activa el temporizador.

Un comportamiento bastante extraño es que cuando un evento de un dedo se cancela por un gesto de dos dedos dentro del período de tiempo permitido, el temporizador se retrasará. Se dispara después de que el evento touchCanceled se llama. Así que tenemos el problema, que tratamos de bloquear el zoom aunque el evento ya está cancelado y por lo tanto desactivar el zoom para el siguiente evento. Para manejar este comportamiento, el método de devolución de llamada timer comprueba si touchesCanceled fue llamado antes. @implementation JWTwoFingerScrollView

#pragma mark -
#pragma mark Event Passing


- (id)initWithCoder:(NSCoder *)coder {
    self = [super initWithCoder:coder];
    if (self) {
        for (UIGestureRecognizer* r in self.gestureRecognizers) {
            if ([r isKindOfClass:[UIPanGestureRecognizer class]]) {
                [((UIPanGestureRecognizer*)r) setMaximumNumberOfTouches:2];
                [((UIPanGestureRecognizer*)r) setMinimumNumberOfTouches:2];
                zoomScale[0] = -1.0;
                zoomScale[1] = -1.0;
            }
            timerWasDelayed = NO;
        }
    }
    return self;
}
-(void)lockZoomScale {    
    zoomScale[0] = self.minimumZoomScale;
    zoomScale[1] = self.maximumZoomScale;
    [self setMinimumZoomScale:self.zoomScale];
    [self setMaximumZoomScale:self.zoomScale];
        NSLog(@"locked %.2f %.2f",self.minimumZoomScale,self.maximumZoomScale);
}
-(void)unlockZoomScale {
    if (zoomScale[0] != -1 && zoomScale[1] != -1) {
        [self setMinimumZoomScale:zoomScale[0]];
        [self setMaximumZoomScale:zoomScale[1]];
        zoomScale[0] = -1.0;
        zoomScale[1] = -1.0;
        NSLog(@"unlocked %.2f %.2f",self.minimumZoomScale,self.maximumZoomScale);
    }
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@"began %i",[event allTouches].count);
    [self setCanCancelContentTouches:YES];
     if ([event allTouches].count == 1){
         touchesBeganTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(firstTouchTimerFired:) userInfo:nil repeats:NO];
         [touchesBeganTimer retain];
         [touchFilter touchesBegan:touches withEvent:event];
     }
 }

//if one finger touch gets canceled by two finger touch, this timer gets delayed
// so we can! use this method to disable zooming, because it doesnt get called when two finger touch events are wanted; otherwise we would disable zooming while zooming
-(void)firstTouchTimerFired:(NSTimer*)timer {
    NSLog(@"fired");
    [self setCanCancelContentTouches:NO];
    //if already locked: unlock
    //this happens because two finger gesture delays timer until touch event finishes.. then we dont want to lock!
    if (timerWasDelayed) {
        [self unlockZoomScale];
    }
    else {
        [self lockZoomScale];
    }
    timerWasDelayed = NO;
 }

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
//    NSLog(@"moved %i",[event allTouches].count);
    [touchFilter touchesMoved:touches withEvent:event];
}

 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@"ended %i",[event allTouches].count);
    [touchFilter touchesEnded:touches withEvent:event];
    [self unlockZoomScale];
 }

 //[self setCanCancelContentTouches:NO];
 -(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@"canceled %i",[event allTouches].count);
    [touchFilter touchesCancelled:touches withEvent:event];
    [self unlockZoomScale];
     timerWasDelayed = YES;
 }

@end

 2
Author: Jan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-28 00:27:14

Malas noticias: iPhone SDK 3.0 y arriba, no pasar toques a -touchesBegan: y -touchesEnded: **UIScrollview**métodos de subclase nunca más. Puede usar los métodos touchesShouldBegin y touchesShouldCancelInContentView que no son los mismos.

Si realmente desea obtener este toque, tenga uno hack que permita esto.

En tu subclase de UIScrollView anula el método hitTest así:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {

  UIView *result = nil;
  for (UIView *child in self.subviews)
    if ([child pointInside:point withEvent:event])
      if ((result = [child hitTest:point withEvent:event]) != nil)
        break;

  return result;
}

Esto le pasará a la subclase este toque, sin embargo, no puede cancelar los toques a UIScrollView superclase.

 1
Author: SEQOY Development Team,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-03 16:48:59

Lo que hago es que mi controlador de vista configure la vista de desplazamiento:

[scrollView setCanCancelContentTouches:NO];
[scrollView setDelaysContentTouches:NO];

Y en mi vista de niño tengo un temporizador porque los toques de dos dedos generalmente comienzan como un dedo seguido rápidamente por dos dedos.:

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    // Hand tool or two or more touches means a pan or zoom gesture.
    if ((selectedTool == kHandToolIndex) || (event.allTouches.count > 1)) {
        [[self parentScrollView] setCanCancelContentTouches:YES];
        [firstTouchTimer invalidate];
        firstTouchTimer = nil;
        return;
    }

    // Use a timer to delay first touch because two-finger touches usually start with one touch followed by a second touch.
    [[self parentScrollView] setCanCancelContentTouches:NO];
    anchorPoint = [[touches anyObject] locationInView:self];
    firstTouchTimer = [NSTimer scheduledTimerWithTimeInterval:kFirstTouchTimeInterval target:self selector:@selector(firstTouchTimerFired:) userInfo:nil repeats:NO];
    firstTouchTimeStamp = event.timestamp;
}

Si aparece un segundo evento touchesBegan: con más de un dedo, la vista de desplazamiento puede cancelar los toques. Por lo tanto, si el usuario se desplaza con dos dedos, esta vista obtendría un mensaje touchesCanceled:.

 1
Author: lucius,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-01-12 06:05:44

Este parece ser el mejor recurso para esta pregunta en internet. Otra solución cercana se puede encontrar aquí.

He resuelto este problema de una manera muy satisfactoria de una manera diferente, esencialmente suplantando mi propio reconocedor de gestos en la ecuación. Recomiendo encarecidamente que cualquiera que esté tratando de lograr el efecto solicitado por el póster original considere esta alternativa sobre la subclase agresiva de UIScrollView.

El siguiente proceso proporcionará:

  • A UIScrollView que contiene su vista personalizada

  • Zoom y Pan con dos dedos (vía UIPinchGestureRecognizer)

  • Procesamiento de eventos de tu vista para todos los demás toques

Primero, supongamos que tiene un controlador de vista y su vista. En IB, convierta la vista en una vista secundaria de una vista de desplazamiento y ajuste las reglas de redimensionamiento de la vista para que no cambie de tamaño. En los atributos de la vista de desplazamiento, active cualquier cosa que diga "rebote" y desactivar "delaysContentTouches". También debe establecer el zoom min y max a otro que el predeterminado de 1.0 para, como dicen los documentos de Apple, esto es necesario para que el zoom funcione.

Cree una subclase personalizada de UIScrollView, y haga de esta vista de desplazamiento esa subclase personalizada. Agregue una toma de corriente a su controlador de vista para el scrollview y conéctelos. Ahora estás totalmente configurado.

Deberá agregar el siguiente código a la subclase UIScrollView para que pase de forma transparente los eventos táctiles (I sospeche que esto podría hacerse de manera más elegante, tal vez incluso pasando por alto la subclase por completo):

#pragma mark -
#pragma mark Event Passing

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.nextResponder touchesBegan:touches withEvent:event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.nextResponder touchesMoved:touches withEvent:event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    [self.nextResponder touchesEnded:touches withEvent:event];
}
- (BOOL)touchesShouldCancelInContentView:(UIView *)view {
    return NO;
}

Agregue este código a su controlador de vista:

- (void)setupGestures {
    UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinchGesture:)];
    [self.view addGestureRecognizer:pinchGesture];
    [pinchGesture release];
}

- (IBAction)handlePinchGesture:(UIPinchGestureRecognizer *)sender {
if ( sender.state == UIGestureRecognizerStateBegan ) {
    //Hold values
    previousLocation = [sender locationInView:self.view];
    previousOffset = self.scrollView.contentOffset;
    previousScale = self.scrollView.zoomScale;
} else if ( sender.state == UIGestureRecognizerStateChanged ) {
    //Zoom
    [self.scrollView setZoomScale:previousScale*sender.scale animated:NO];

    //Move
    location = [sender locationInView:self.view];
    CGPoint offset = CGPointMake(previousOffset.x+(previousLocation.x-location.x), previousOffset.y+(previousLocation.y-location.y));
    [self.scrollView setContentOffset:offset animated:NO];  
} else {
    if ( previousScale*sender.scale < 1.15 && previousScale*sender.scale > .85 )
        [self.scrollView setZoomScale:1.0 animated:YES];
}

}

Tenga en cuenta que en este método hay referencias a una serie de propiedades que debe definir en los archivos de clase de su controlador de vista:

  • CGFloat previousScale;
  • CGPoint previousOffset;
  • CGPoint previousLocation;
  • CGPoint location;

Ok eso es todo!

Desafortunadamente yo no pude obtener el ScrollView para mostrar sus scrollers durante el gesto. Probé todas estas estrategias:

//Scroll indicators
self.scrollView.showsVerticalScrollIndicator = YES;
self.scrollView.showsVerticalScrollIndicator = YES;
[self.scrollView flashScrollIndicators];
[self.scrollView setNeedsDisplay];

Una cosa que realmente disfruté es que si miras la última línea, notarás que agarra cualquier zoom final que esté alrededor del 100% y solo lo redondea a eso. Puedes ajustar tu nivel de tolerancia; había visto esto en el comportamiento de zoom de Pages y pensé que sería un buen toque.

 1
Author: SG1,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-04 13:18:04

Echa un vistazo a mi solución :

#import “JWTwoFingerScrollView.h”

@implementation JWTwoFingerScrollView

- (id)initWithCoder:(NSCoder *)coder {
    self = [super initWithCoder:coder];
    if (self) {
        for (UIGestureRecognizer* r in self.gestureRecognizers) {
            NSLog(@“%@”,[r class]);
            if ([r isKindOfClass:[UIPanGestureRecognizer class]]) {
                [((UIPanGestureRecognizer*)r) setMaximumNumberOfTouches:2];
                [((UIPanGestureRecognizer*)r) setMinimumNumberOfTouches:2];
            }
        }
    }
    return self;
}

-(void)firstTouchTimerFired:(NSTimer*)timer {
    [self setCanCancelContentTouches:NO];
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self setCanCancelContentTouches:YES];
    if ([event allTouches].count == 1){
        touchesBeganTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(firstTouchTimerFired:) userInfo: nil repeats:NO];
        [touchesBeganTimer retain];
        [touchFilter touchesBegan:touches withEvent:event];
    }
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    [touchFilter touchesMoved:touches withEvent:event];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@“ended %i”,[event allTouches].count);
    [touchFilter touchesEnded:touches withEvent:event];
}

-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    NSLog(@“canceled %i”,[event allTouches].count);
    [touchFilter touchesCancelled:touches withEvent:event];
}

@end

No retrasa el primer toque y no se detiene cuando el usuario toca con dos dedos después de usar uno. Aún así, permite cancelar un evento one touch recién iniciado usando un temporizador.

 0
Author: Jan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-19 23:03:19

Sí, necesitarás subclase UIScrollView y anular sus métodos -touchesBegan: y -touchesEnded: para pasar toques "arriba". Esto probablemente también implicará que la subclase tenga una variable miembro UIView para que sepa a qué se debe pasar los retoques.

 0
Author: anisoptera,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-04 13:16:50

Poner esto en el método viewDidLoad y esto logra el desplazamiento de la vista de la manipulación de los dos toque pan comportamiento y otro gesto de desplazamiento controlador de manejo de one touch panorámica de comportamiento -->

scrollView.panGestureRecognizer.minimumNumberOfTouches = 2

let panGR = UIPanGestureRecognizer(target: self, action: #selector(ViewController.handlePan(_:)))
panGR.minimumNumberOfTouches = 1
panGR.maximumNumberOfTouches = 1

scrollView.gestureRecognizers?.append(panGR)

Y en el método handlePan, que es una función adjunta al ViewController, simplemente hay una instrucción print para verificar que se está ingresando el método > >

@IBAction func handlePan(_ sender: UIPanGestureRecognizer) {
    print("Entered handlePan numberOfTuoches: \(sender.numberOfTouches)")
}

HTH

 0
Author: Adam Freeman,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-02 02:33:07

Respuesta de Kenshi en Swift 4

for gestureRecognizer: UIGestureRecognizer in self.gestureRecognizers! {
    if (gestureRecognizer is UIPanGestureRecognizer) {
        let panGR = gestureRecognizer as? UIPanGestureRecognizer
        panGR?.minimumNumberOfTouches = 2
    }
}
 0
Author: tnylee,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-22 15:25:49