Você pode anexar um UIGestureRecognizer a vários modos de exibição?

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

No código acima, apenas os toques view2são reconhecidos. Se eu comentar a terceira linha, os toques view1são reconhecidos. Se eu estiver certo e você só puder usar um reconhecedor de gestos uma vez, não tenho certeza se isso é um bug ou se precisa de mais documentação.

kubi
fonte

Respostas:

334

A UIGestureRecognizerdeve ser usado com uma única visualização. Concordo que a documentação é irregular. Que UIGestureRecognizerpossui uma única viewpropriedade, revela:

Visão

A visualização à qual o reconhecedor de gestos está anexado. (somente leitura)

@property (não atômica, somente leitura) UIView * view

Discussão Você anexa (ou adiciona) um reconhecedor de gesto a um objeto UIView usando o método addGestureRecognizer:.

TomSwift
fonte
11
Como a adição de um reconhecedor de gestos a uma exibição acontece no tempo de execução (versus o tempo de compilação).
TomSwift
1
Entendi isso, mas muito parecido com detectar que digamos que não usamos uma variável, o XCode percebeu com base no código que passamos o mesmo reconhecedor para várias visualizações e poderia avisar o codificador.
Zoltán Matók
1
O aviso do compilador sobre várias visualizações atribuindo o mesmo UITapGestureRecognizer é um disparate, porque você pode fazer isso de propósito, por exemplo, se desejar mover o reconhecedor de gestos de toque de uma visualização para outra. Dito isto, é uma limitação tola que o reconhecedor de gestos não possa ser usado em várias visualizações.
Erik van der Neut
1
O iOS 9 agora impõe uma única visualização por reconhecedor de gestos, eu estava usando o método do construtor de interface abaixo, mas agora recebo a seguinte mensagem quando tento usá-lo (alguns detalhes são breves): AVISO: um reconhecedor de gestos (< O UITapGestureRecognizer: .....>) foi configurado em um storyboard / xib para ser adicionado a mais de uma visualização (-> <UIView:; frame = (0 44; 600 536); autoresize = RM + BM; GestRecognizers = < NSArray ...:>; layer = <CALayer: ... >>) de cada vez, isso nunca foi permitido e agora é imposto. A partir do iOS 9.0, ele será colocado na primeira visualização em que é carregado.
George Brown
Se você está adicionando à vista no segundo tempo, a vista foi anexado antes que por este reconhecedor está ficando solto automaticamente UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didPressed:)]; [self.view1 addGestureRecognizer:tapRecognizer]; [self.view2 addGestureRecognizer:tapRecognizer];saída view1 não tem variedade gesto reconhecedores; view2 tem variedade gesto reconhecedores
kokos8998
48

Eu consegui contornar isso usando o abaixo.

for (UIButton *aButton in myButtons) {

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

}

Então, no meu método handleLongPress, apenas defino um UIButton igual à exibição do reconhecedor de gestos e ramifico o que faço com base nesse botão

- (void)handleLongPress:(UILongPressGestureRecognizer*)gesture {
    if ( gesture.state == UIGestureRecognizerStateEnded ) {
        UIButton *whichButton=(UIButton *)[gesture view];
        selectedButton=(UIButton *)[gesture view];
    ....
}
kwalker
fonte
1
Ótima resposta.Obrigado por uma tonelada. Esta poderia ter sido a resposta aceita se a pergunta fosse "Como você anexa um UIGestureRecognizer a várias visualizações?"
D_D 15/02
7
Isso (ou algo muito próximo disso) não funcionou para mim. Adicionei várias visualizações a um reconhecedor de gestos de toque no Interface Builder e conectei o reconhecedor a uma ação. A ação era chamada sempre que uma visualização anexada era tocada, mas o gesto.view era sempre a última visualização anexada.
Aneil Mallavarapu
Esta é uma resposta muito boa e também muito útil e concordo com o @MicRO +1
Dilip
2
Aneil, isso é porque você não criou novas instâncias do reconhecedor de gestos. O que está acontecendo no loop nesta resposta aqui é que novas instâncias de reconhecedores de gestos são criadas, cada uma com apenas uma visualização anexada. Todos eles podem apontar para o mesmo manipulador, onde você verifica a visualização para ver qual deles foi tocado.
Erik van der Neut
1
Alguém pode confirmar que isso não funciona mais na versão atual do Obj-C / Swift?
Max1 Mus
18

Para Swift 3, no caso de alguém exigir isso: Baseado na resposta de Bhavik Rathod acima.

 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
fonte
3
isso é basicamente criar vários gestos para as duas visualizações, ainda a mesma regra: todo gesto tem apenas uma visão a ser anexada.
Abdoelrhman
3
Não, a função cria um gesto toda vez que é chamada
Abdoelrhman
2
o nome da função está incorreto. a função lógica aqui é uma função de obtenção. por isso deve ser nomeado: getGestureRecognizeporque é isso que esta função faz
David Procure
Trabalhe bem para mim! E código mais limpo do que criar múltiplas variáveis ou colocar o código inteiro para a criação dentro addGestureRecognizer
Codenator81
11

Podemos fazer algo assim, é fácil e simples

1) crie a função como abaixo em seu controlador (esta função retornará GestureRecognizer)

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

2) agora defina esse reconhecedor em várias visualizações

[self.view1 addGestureRecognizer:[self setRecognizer]]; 
[self.view2 addGestureRecognizer:[self setRecognizer]];
Bhavik Rathod
fonte
Não está funcionando para mim quando uso dois rótulos em vez de visualizações.
Mihir Oza
3
@Mihir Oza, não pode funcionar diretamente para UILabels. Por causa dos rótulos, não há sentido para a interação do usuário. Se você deseja adicionar gestos para UILabels, adicione esta única linha labelName..isUserInteractionEnabled = true no Swift. Em seguida, adicione gestos.
iOS
É tarde demais, cara, eu já arrumei isso. Mas obrigado pela sugestão. Seu comentário será útil para usuários de pilha. Estimado!
Mihir Oza
1
Eu acho que a linha setNumberOfTapsRequired:1não é necessária
Naveed Abbas
9

Não, você não deve anexar reconhecedores de gestos a mais de uma visualização.

Há essas informações explícitas na documentação da Apple:

Os reconhecedores de gestos são anexados a uma exibição

Todo reconhecedor de gestos está associado a uma visualização. Por outro lado, uma visão pode ter vários reconhecedores de gestos, porque uma única visão pode responder a muitos gestos diferentes. Para um reconhecedor de gestos reconhecer toques que ocorrem em uma exibição específica, você deve anexar o reconhecedor de gestos a essa exibição.

Guia de manipulação de eventos para iOS - Apple Developer Library

Enquanto outros mencionam que podem funcionar em alguns casos, isso é claramente contrário à documentação e pode mudar em qualquer versão futura do iOS.

O que você pode fazer é adicionar reconhecedores de gestos separados às visualizações que você deseja monitorar e eles podem compartilhar uma ação comum.

Joseph Lord
fonte
4

Bem, se alguém não quiser codificar para adicionar exibição de gestos para vários botões, como o kwalker respondeu acima, e quiser fazê-lo através do Interface Builder, isso pode ajudá-lo.

1) Você pode adicionar o reconhecimento de gestos de pressão longa na Biblioteca de objetos, como adicionar outros objetos como UIButtons e UILabels.

insira a descrição da imagem aqui Inicialmente o que acabei usando foi que peguei apenas um

2) Defina pontos de referência UIButtone ações enviadas com o proprietário do arquivo.

insira a descrição da imagem aqui

Nota: Se você tiver vários UIButton ou qualquer outro objeto, precisará de um reconhecedor de gestos separado para cada um deles. Para mais detalhes, consulte esta pergunta minha. Falha na etiqueta UIButton no reconhecedor de gestos de pressão longa

rohan-patel
fonte
É muito fácil vincular mais de um UIView ao reconhecedor de hóspedes usando o IB. A questão era sobre geração de código.
AlexeyVMP
3

se você tiver uma visão fixa, sugiro que você faça algo assim

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

dessa forma reduzirá várias variáveis ​​inúteis diferentes

Raynaldio Limarga
fonte
3

Você pode criar uma extensão genérica à vista para adicionar reconhecedores de gestos facilmente. Este é apenas um exemplo, mas poderia ser assim

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 adicionar um reconhecedor de 2 toques em uma visualização, basta ligar para:

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

Você também pode adicionar facilmente um reconhecedor de furto

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

e assim por diante. Lembre-se de que o destino deve estar vinculado ao seletor.

Martin
fonte
2

Substituir classe por " <UIScrollViewDelegate>"

E use este método na classe .m:

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

Este método ajudará você a ativar vários furtos em uma única exibição.

AnkitRox
fonte
2

Que tal reescrever (recriar) seu GestureRecognize sempre que você adicionar um reconhecedor de gestos apontando para a mesma função. No caso abaixo, ele funciona. Eu estou 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
fonte
-6

Você pode fazer isso usando este código, minhas visualizações, que são visualizações de imagens no 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
fonte
1
Você está criando vários reconhecedores de gestos; minha pergunta original era sobre a reutilização de um único reconhecedor de gestos, o que você não pode fazer.
Kubi #
1
Qual o sentido de adicionar 500a todas as tags de suas visualizações e subtrair 500? Por que não começar suas tags no 1(ou até 0) em vez de 501?
precisa saber é o seguinte
@MattDiPasquale, Não importa se você deseja começar com o 1seu apenas eu copiei esse código do meu aplicativo de onde estou fornecendo 501. Mas sim, não dê 0bcoz. Eu li em algum lugar que sempre indica a visão dos pais, para que isso crie complicações. Acredite, eu já enfrentei isso.
Dilip
O texto principal da documentação é "A exibição estabelece uma forte referência ao reconhecedor de gestos". o que significa que a visão possui o gesto. O gesto pode ter apenas um proprietário. Veja o link
Phantom59