¿Se puede adjuntar un UIGestureRecognizer a varias vistas?

228
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapTapTap:)];
[self.view1 addGestureRecognizer:tapGesture];
[self.view2 addGestureRecognizer:tapGesture];
[tapGesture release];

En el código anterior solo view2se reconocen los grifos . Si comento la tercera línea, view1se reconocen los grifos . Si estoy en lo cierto y solo puede usar un reconocedor de gestos una vez, no estoy seguro de si se trata de un error o si solo necesita más documentación.

kubi
fuente

Respuestas:

334

A UIGestureRecognizerse debe utilizar con una sola vista. Estoy de acuerdo en que la documentación es irregular. Que UIGestureRecognizertiene una sola viewpropiedad lo regala:

ver

La vista a la que está asociado el reconocedor de gestos. (solo lectura)

@property (no atómica, solo lectura) vista UIView *

Discusión Usted adjunta (o agrega) un reconocedor de gestos a un objeto UIView usando el método addGestureRecognizer:

TomSwift
fuente
11
Porque agregar un reconocedor de gestos a una vista ocurre en tiempo de ejecución (vs. tiempo de compilación).
TomSwift
1
Entendí eso, pero al igual que detectar que dicen que no hemos usado una variable, XCode podría decir, según el código, que hemos pasado el mismo reconocedor a varias vistas y podría advertir al codificador.
Zoltán Matók
1
La advertencia del compilador sobre múltiples vistas que asignan el mismo UITapGestureRecognizer no tiene sentido, porque es posible que desee hacer esto a propósito, por ejemplo, si desea mover el reconocedor de gestos de toque de una vista a otra. Dicho esto, es una limitación tonta que el reconocedor de gestos no se pueda usar en múltiples vistas.
Erik van der Neut
1
iOS 9 ahora impone una vista única por reconocedor de gestos, había estado usando el siguiente método de creación de interfaz, pero ahora recibo el siguiente mensaje cuando trato de usarlo (algunos detalles cortados por brevedad): ADVERTENCIA: Un reconocedor de gestos (< UITapGestureRecognizer: .....>) se configuró en un guión gráfico / xib para agregarse a más de una vista (-> <UIView:; frame = (0 44; 600 536); autoresize = RM + BM; gestoRecognizers = < NSArray ...:>; layer = <CALayer: ... >>) a la vez, esto nunca se permitió, y ahora se aplica. A partir de iOS 9.0, se colocará en la primera vista en la que se cargue.
George Brown
Si está agregando a la vista por segunda vez, la vista se adjuntó antes de que este reconocedor se desatara automáticamente UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didPressed:)]; [self.view1 addGestureRecognizer:tapRecognizer]; [self.view2 addGestureRecognizer:tapRecognizer];La vista de salida1 no tiene una matriz de reconocedores de gestos; view2 tiene una matriz de reconocedores de gestos
kokos8998
48

Lo solucioné usando el siguiente.

for (UIButton *aButton in myButtons) {

            UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
            longPress.minimumPressDuration=1.0;
            [aButton addGestureRecognizer:longPress];
            [longPress release];

}

Luego, en mi método handleLongPress, acabo de establecer un UIButton igual a la vista del reconocedor de gestos y ramifico lo que hago en función de ese botón

- (void)handleLongPress:(UILongPressGestureRecognizer*)gesture {
    if ( gesture.state == UIGestureRecognizerStateEnded ) {
        UIButton *whichButton=(UIButton *)[gesture view];
        selectedButton=(UIButton *)[gesture view];
    ....
}
kwalker
fuente
1
Gran respuesta. Muchas gracias. Esta podría haber sido la respuesta aceptada si la pregunta era "¿Cómo adjuntar un UIGestureRecognizer a varias vistas?"
D_D
77
Esto (o algo muy parecido a esto) no funcionó para mí. Agregué varias vistas a un reconocedor de gestos de toque en Interface Builder y conecté el reconocedor a una acción. La acción se llamaba cada vez que se tocaba una vista adjunta, pero gesto.vista siempre era la última vista adjunta.
Aneil Mallavarapu
Esta es una muy buena respuesta y también muy útil y de acuerdo con @MicRO +1
Dilip
2
Aneil, eso es porque no creaste nuevas instancias del reconocedor de gestos. Lo que sucede en el bucle de esta respuesta aquí es que se crean nuevas instancias de reconocedores de gestos, cada una con solo una vista adjunta. Todos pueden apuntar al mismo controlador, donde luego verifica la vista para ver cuál se tocó.
Erik van der Neut
1
¿Alguien más puede confirmar que esto ya no funciona en la versión actual de Obj-C / Swift?
Maxi Mus
18

Para Swift 3 en caso de que alguien requiera esto: Basado en la respuesta de Bhavik Rathod anterior.

 func setGestureRecognizer() -> UIPanGestureRecognizer {

        var panRecognizer = UIPanGestureRecognizer()

        panRecognizer = UIPanGestureRecognizer (target: self, action: #selector(pan(panGesture:)))
        panRecognizer.minimumNumberOfTouches = 1
        panRecognizer.maximumNumberOfTouches = 1
        return panRecognizer
    }

        ///set the recognize in multiple views
        view1.addGestureRecognizer(setGestureRecognizer())
        view2.addGestureRecognizer(setGestureRecognizer())
George Asda
fuente
3
eso es básicamente crear múltiples gestos para las dos vistas, sigue siendo la misma regla: cada gesto tiene solo una vista para adjuntar
Abdoelrhman
3
No, la función crea un gesto cada vez que se llama
Abdoelrhman
2
El nombre de la función es incorrecto. La función lógica aquí es una función de obtención. entonces debería llamarse: getGestureRecognizeporque eso es lo que hace esta función
David Seek
¡Trabaja bien para mí! Y codifique más limpio que crear múltiples variables o poner código completo para la creación dentro de addGestureRecognizer
Codenator81
11

Podemos hacer algo como esto, es fácil y simple

1) cree la función como se muestra a continuación en su controlador (esta función devolverá GestureRecognizer)

-(UITapGestureRecognizer*)setRecognizer{
     UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(openProfile)];
     [gestureRecognizer setNumberOfTapsRequired:1];
     return gestureRecognizer;
}

2) ahora configure este reconocedor en múltiples vistas

[self.view1 addGestureRecognizer:[self setRecognizer]]; 
[self.view2 addGestureRecognizer:[self setRecognizer]];
Bhavik Rathod
fuente
No me funciona cuando uso dos etiquetas en lugar de vistas.
Mihir Oza
3
@Mihir Oza, no puede funcionar para UILabels directamente. Debido a las etiquetas no tiene sentido para la interacción del usuario. Si desea agregar gestos para UILabels agregue esta línea simple labelName..isUserInteractionEnabled = true en Swift. Luego agrega gestos.
iOS
Es demasiado tarde, hombre, ya lo arreglé. Pero gracias por la sugerencia. Su comentario será útil para los usuarios de la pila. ¡Apreciado!
Mihir Oza
1
Supongo que la línea setNumberOfTapsRequired:1no es necesaria
Naveed Abbas
9

No, no debe adjuntar reconocedores de gestos a más de una vista.

Existe esta información explícita en la documentación de Apple:

Los reconocedores de gestos se adjuntan a una vista

Cada reconocedor de gestos está asociado con una vista. Por el contrario, una vista puede tener múltiples reconocedores de gestos, porque una sola vista puede responder a muchos gestos diferentes. Para que un reconocedor de gestos reconozca toques que ocurren en una vista particular, debe adjuntar el reconocedor de gestos a esa vista.

Guía de manejo de eventos para iOS: reconocedores de gestos Biblioteca de desarrolladores de Apple de

Si bien, como otros mencionan, podrían funcionar en algunos casos, está claramente en contra de la documentación y podría cambiar en cualquier versión futura de iOS.

Lo que puede hacer es agregar reconocedores de gestos separados a las vistas que desea monitorear y pueden compartir una acción común.

Joseph Lord
fuente
4

Bueno, si alguien no quiere codificar para agregar la vista de gestos para varios botones como kwalker ha respondido anteriormente, y desea hacerlo a través de Interface Builder, esto puede ayudarlo.

1) Puede agregar el Reconocimiento de gestos de pulsación larga desde la Biblioteca de objetos al igual que agrega otros objetos como UIButtons y UILabels.

ingrese la descripción de la imagen aquí Inicialmente, lo que terminé usando fue que tomé solo uno

2) Establecer salidas de referencia UIButtony acciones enviadas con el Propietario del archivo.

ingrese la descripción de la imagen aquí

Nota: Si tiene múltiples UIButton o cualquier otro objeto, necesitará un reconocedor de gestos separado para cada uno de ellos. Para más detalles, consulte esta pregunta mía. Obtener una etiqueta UIButton incorrecta en el reconocedor de gestos de pulsación larga

rohan-patel
fuente
Es muy fácil vincular más de un UIView al reconocedor de invitados con IB. La pregunta era sobre la generación de código.
AlexeyVMP
3

si tienes vista fija te sugiero que hagas algo como esto

[self.view1 addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapTapTap:)]];
[self.view2 addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapTapTap:)]];

de esa manera reducirá múltiples variables inútiles diferentes

Raynaldio Limarga
fuente
3

Puede crear una extensión genérica a la vista para agregar reconocedores de gestos fácilmente. Este es solo un ejemplo, pero podría verse así

extension UIView {

    func setGestureRecognizer<Gesture: UIGestureRecognizer>(of type: Gesture.Type, target: Any, actionSelector: Selector, swipeDirection: UISwipeGestureRecognizer.Direction? = nil, numOfTaps: Int = 1) {
    let getRecognizer = type.init(target: target, action: actionSelector)

    switch getRecognizer {
    case let swipeGesture as UISwipeGestureRecognizer:
        guard let direction = swipeDirection else { return }
        swipeGesture.direction = direction
        self.addGestureRecognizer(swipeGesture)
    case let tapGesture as UITapGestureRecognizer:
        tapGesture.numberOfTapsRequired = numOfTaps
        self.addGestureRecognizer(tapGesture)
    default:
        self.addGestureRecognizer(getRecognizer)
    }
  }

}

Para agregar un reconocedor de 2 toques en una vista, simplemente llame:

let actionSelector = #selector(actionToExecute)
view.setGestureRecognizer(of: UITapGestureRecognizer.self, target: self, actionSelector: actionSelector, numOfTaps: 2)

También podría agregar fácilmente un reconocedor de deslizamiento

view.setGestureRecognizer(of: UISwipeGestureRecognizer.self, target: self, actionSelector: actionSelector, swipeDirection: .down)

y así. Solo recuerda que el objetivo debe estar vinculado al selector.

Martín
fuente
2

Anular clase por ' <UIScrollViewDelegate>'

Y use este método en la clase .m:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
    return YES;
}

Este método lo ayudará a habilitar el deslizamiento múltiple en una sola vista.

AnkitRox
fuente
2

¿Qué pasa con reescribir (recrear) su GestureRecognize cada vez que agrega un reconocedor de gestos que apunta a la misma función? En el caso de abajo funciona. Estoy usando IBOutletCollection

Swift 2:

@IBOutlet var topicView: [UIView]!

override func viewDidLoad() {
        for view in self.topicView as [UIView] {
        view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: "viewClicked:"))
    }
}

func viewClicked(recognizer: UITapGestureRecognizer) {
    print("tap")
}
Febaisi
fuente
-6

Puede hacerlo utilizando este código mis vistas, que son vistas de imágenes en el xib.

- (void)viewDidLoad
{
    firstIV.tag = 501;
    secondIV.tag = 502;
    thirdIV.tag = 503;
    forthIV.tag = 504;

    [self addTapGesturetoImageView: firstIV];
    [self addTapGesturetoImageView: secondIV];
    [self addTapGesturetoImageView: thirdIV];
    [self addTapGesturetoImageView: forthIV];
}

-(void)addTapGesturetoImageView:(UIImageView*)iv
{
    iv.userInteractionEnabled = YES;
    UITapGestureRecognizer * textfielBGIVTapGasture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(textfielBGIVTapped:)];
    textfielBGIVTapGasture.numberOfTapsRequired = 1;
    [iv addGestureRecognizer:textfielBGIVTapGasture];
}

- (void)textfielBGIVTapped:(UITapGestureRecognizer *)recognizer {
    int tag = recognizer.view.tag-500;
    switch (tag) {
        case 1:
        {
            //firstIV tapped;
            break;
        }
        case 2:
        {
            //secondIV tapped;
            break;
        }
        case 3:
        {
            //thirdIV tapped;
            break;
        }
        case 4:
        {
            //forthIV tapped;
            break;
        }
        default: {
            break;
        }
    }
}
Dilip
fuente
1
Estás creando múltiples reconocedores de gestos; Mi pregunta original era sobre la reutilización de un reconocedor de gesto único, que no puede hacer.
kubi
1
¿Cuál es el punto de agregar 500a todas las etiquetas de sus vistas y luego restar 500? ¿Por qué no simplemente comenzar sus etiquetas en 1(o incluso 0) en lugar de 501?
ma11hew28
@MattDiPasquale, no importa si desea comenzar con el 1solo he copiado este código de mi aplicación de donde lo estoy dando 501. Pero sí, no le des 0porque he leído en alguna parte que siempre indica la vista de los padres, por lo que creará una complicación. Créeme, lo he enfrentado.
Dilip
El texto clave en la documentación es "La vista establece una fuerte referencia al reconocedor de gestos". lo que significa que la vista posee el gesto. El gesto solo puede tener un propietario. Ver enlace
Phantom59