UIGestureRecognizer em UIImageView

179

Eu tenho um UIImageView, que eu quero poder redimensionar e girar etc.

Pode UIGestureRecognizerser adicionado ao UIImageView?

Gostaria de adicionar um reconhecedor de rotação e pitada para um UIImageViewque seria criado em tempo de execução.

Como alguém adiciona esses reconhecedores?

sistema
fonte

Respostas:

426

Verifique se userInteractionEnabledestá YESno UIImageView. Depois, você pode adicionar um reconhecedor de gestos.

imageView.userInteractionEnabled = YES;
UIPinchGestureRecognizer *pgr = [[UIPinchGestureRecognizer alloc] 
    initWithTarget:self action:@selector(handlePinch:)];
pgr.delegate = self;
[imageView addGestureRecognizer:pgr];
[pgr release];
:
:
- (void)handlePinch:(UIPinchGestureRecognizer *)pinchGestureRecognizer
{
  //handle pinch...
}
Abubakr Dar
fonte
5
Não, isso apenas mostra como adicionar os reconhecedores de gestos. Você precisa fazer o zoom real / girar você mesmo nos manipuladores de gestos. Veja o aplicativo de amostra Touches_GestureRecognizers sobre como fazer o zoom / girar.
77
O +1 ficou aqui por vários anos, tentando descobrir por que meus gestos não funcionariam .. "Verifique se userInteractionEnabled está SIM no UIImageView." Obrigado!
quer
1
Isso definitivamente facilitou meu trabalho do que tentar definir limites em um reconhecedor definido para a visualização geral. Obrigado!
Josh Kovach
6
imageView.userInteractionEnabled = SIM; essa é a chave! Obrigado.
HamasN
3
userInteractionEnabledainda tem de ser definido para SIM / verdadeiro no Xcode 8 Objectivo-C / Swift
Anat
76

Sim, um UIGestureRecognizer pode ser adicionado a um UIImageView. Conforme indicado na outra resposta, é muito importante lembrar de ativar a interação do usuário na visualização da imagem, definindo sua userInteractionEnabledpropriedade como YES. UIImageView herda de UIView, cuja propriedade de interação do usuário é definida como YESpadrão, no entanto, a propriedade de interação do usuário de UIImageView é definida como NOpadrão.

Nos documentos do UIImageView:

Novos objetos de exibição de imagem são configurados para desconsiderar eventos do usuário por padrão. Se você quiser manipular eventos em uma subclasse personalizada de UIImageView, altere explicitamente o valor da propriedade userInteractionEnabled para YES depois de inicializar o objeto.

Enfim, na maior parte da resposta. Aqui está um exemplo de como criar a UIImageViewcom a UIPinchGestureRecognizer, a UIRotationGestureRecognizere a UIPanGestureRecognizer.

Primeiro, em viewDidLoadou em outro método de sua escolha, crie uma visualização de imagem, forneça uma imagem, um quadro e ative a interação do usuário. Em seguida, crie os três gestos da seguinte maneira. Certifique-se de utilizar a propriedade delegada (provavelmente definida como auto). Isso será necessário para usar vários gestos ao mesmo tempo.

- (void)viewDidLoad
{
    [super viewDidLoad];

    // set up the image view
    UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"someImage"]];
    [imageView setBounds:CGRectMake(0.0, 0.0, 120.0, 120.0)];
    [imageView setCenter:self.view.center];
    [imageView setUserInteractionEnabled:YES]; // <--- This is very important

    // create and configure the pinch gesture
    UIPinchGestureRecognizer *pinchGestureRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchGestureDetected:)];
    [pinchGestureRecognizer setDelegate:self];
    [imageView addGestureRecognizer:pinchGestureRecognizer];

    // create and configure the rotation gesture
    UIRotationGestureRecognizer *rotationGestureRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotationGestureDetected:)];
    [rotationGestureRecognizer setDelegate:self];
    [imageView addGestureRecognizer:rotationGestureRecognizer];

    // creat and configure the pan gesture
    UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureDetected:)];
    [panGestureRecognizer setDelegate:self];
    [imageView addGestureRecognizer:panGestureRecognizer];


    [self.view addSubview:imageView]; // add the image view as a subview of the view controllers view
}

Aqui estão os três métodos que serão chamados quando os gestos em sua exibição forem detectados. Dentro deles, verificaremos o estado atual do gesto e, se ele estiver iniciado ou alterado UIGestureRecognizerState, leremos a propriedade de escala / rotação / tradução do gesto, aplicaremos esses dados a uma transformação afim, aplicaremos a transformação afim à imagem visualizar e, em seguida, redefinir a escala de gestos / rotação / translação.

- (void)pinchGestureDetected:(UIPinchGestureRecognizer *)recognizer
{
    UIGestureRecognizerState state = [recognizer state];

    if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged)
    {
        CGFloat scale = [recognizer scale];
        [recognizer.view setTransform:CGAffineTransformScale(recognizer.view.transform, scale, scale)];
        [recognizer setScale:1.0];
    }
}

- (void)rotationGestureDetected:(UIRotationGestureRecognizer *)recognizer
{
    UIGestureRecognizerState state = [recognizer state];

    if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged)
    {
        CGFloat rotation = [recognizer rotation];
        [recognizer.view setTransform:CGAffineTransformRotate(recognizer.view.transform, rotation)];
        [recognizer setRotation:0];
    }
}

- (void)panGestureDetected:(UIPanGestureRecognizer *)recognizer
{
    UIGestureRecognizerState state = [recognizer state];

    if (state == UIGestureRecognizerStateBegan || state == UIGestureRecognizerStateChanged)
    {
        CGPoint translation = [recognizer translationInView:recognizer.view];
        [recognizer.view setTransform:CGAffineTransformTranslate(recognizer.view.transform, translation.x, translation.y)];
        [recognizer setTranslation:CGPointZero inView:recognizer.view];
    }
}

Finalmente e muito importante, você precisará utilizar o método UIGestureRecognizerDelegategestureRecognizer: shouldRecognizeSimultaneouslyWithGestureRecognizer para permitir que os gestos funcionem ao mesmo tempo. Se esses três gestos são os únicos três que têm essa classe atribuída como delegada, basta retornar YEScomo mostrado abaixo. No entanto, se você tiver gestos adicionais que tenham essa classe atribuída como delegada, poderá ser necessário adicionar lógica a esse método para determinar qual gesto é o que antes de permitir que todos trabalhem juntos.

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

Não se esqueça de garantir que sua classe esteja em conformidade com o protocolo UIGestureRecognizerDelegate . Para fazer isso, verifique se sua interface se parece com isso:

@interface MyClass : MySuperClass <UIGestureRecognizerDelegate>

Se você preferir jogar com o código em um projeto de exemplo funcional, o projeto de exemplo que eu criei contendo esse código pode ser encontrado aqui.

Mick MacCallum
fonte
1
Esta é de longe a melhor resposta que eu já vi no stackoverflow.com, totalmente detalhada, bem comentada e até inclui código fonte no git. Obrigado por isso
Alejandro Luengo
1
Claro, passo a passo, explicação incrível
Alvin
1
Obrigado, que fez em uma página ou duas o que várias dezenas de tutoriais ao longo dos anos pela Apple e outros deixaram de fazer. Eu sinto que deve haver muitas outras coisas no iOS que são possíveis, mas devido à ofuscação e mal-entendidos, elas estão perdidas para nós.
Zack Morris
Ótima resposta, a melhor. Muito obrigado pela sua paciência.
Jorg B Jorge
13

Swift 4.2

myImageView.isUserInteractionEnabled = true
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(imageTapped))
tapGestureRecognizer.numberOfTapsRequired = 1
myImageView.addGestureRecognizer(tapGestureRecognizer)

e quando tocado:

@objc func imageTapped(_ sender: UITapGestureRecognizer) {
   // do something when image tapped
   print("image tapped")
}
ayalcinkaya
fonte
11

Solução Swift 2.0

Você cria um reconhecedor de gesto para tocar, apertar ou deslizar na mesma mansão. Abaixo, mostrarei 4 etapas para colocar o reconhecedor em funcionamento.

4 Passos

1.) Herde de UIGestureRecognizerDelegateadicionando-o à sua assinatura de classe.

class ViewController: UIViewController, UIGestureRecognizerDelegate {...}

2.) Controle o arrasto da sua imagem para o seu viewController para criar um IBOutlet:

@IBOutlet weak var tapView: UIImageView!

3.) No seu viewDidLoad, adicione o seguinte código:

// create an instance of UITapGestureRecognizer and tell it to run 
// an action we'll call "handleTap:"
let tap = UITapGestureRecognizer(target: self, action: Selector("handleTap:"))
// we use our delegate
tap.delegate = self
// allow for user interaction
tapView.userInteractionEnabled = true
// add tap as a gestureRecognizer to tapView
tapView.addGestureRecognizer(tap)

4.) Crie a função que será chamada quando tocar no reconhecedor de gestos. (Você pode excluir o = nilse você escolher).

func handleTap(sender: UITapGestureRecognizer? = nil) {
    // just creating an alert to prove our tap worked!
    let tapAlert = UIAlertController(title: "hmmm...", message: "this actually worked?", preferredStyle: UIAlertControllerStyle.Alert)
    tapAlert.addAction(UIAlertAction(title: "OK", style: .Destructive, handler: nil))
    self.presentViewController(tapAlert, animated: true, completion: nil)
}

Seu código final deve ser algo como isto:

class ViewController: UIViewController, UIGestureRecognizerDelegate {

    @IBOutlet weak var tapView: UIImageView!

    override func viewDidLoad() {
        super.viewDidLoad()

        let tap = UITapGestureRecognizer(target: self, action: Selector("handleTap:"))
        tap.delegate = self
        tapView.userInteractionEnabled = true
        tapView.addGestureRecognizer(tap)
    }

    func handleTap(sender: UITapGestureRecognizer? = nil) {
        let tapAlert = UIAlertController(title: "hmmm...", message: "this actually worked?", preferredStyle: UIAlertControllerStyle.Alert)
        tapAlert.addAction(UIAlertAction(title: "OK", style: .Destructive, handler: nil))
        self.presentViewController(tapAlert, animated: true, completion: nil)
    }
}
Dan Beaulieu
fonte
1
Eu escrevi um blog sobre isso aqui: codebeaulieu.com/3/UIGestureRecognier-programatically
Dan Beaulieu
6

Acabei de fazer isso com o swift4 adicionando 3 gestos em uma única exibição

  1. UIPinchGestureRecognizer : zoom in e zoom out view.
  2. UIRotationGestureRecognizer : gire a exibição.
  3. UIPanGestureRecognizer : arrastando a exibição.

Aqui meu código de exemplo

class ViewController: UIViewController: UIGestureRecognizerDelegate{
      //your image view that outlet from storyboard or xibs file.
     @IBOutlet weak var imgView: UIImageView!
     // declare gesture recognizer
     var panRecognizer: UIPanGestureRecognizer?
     var pinchRecognizer: UIPinchGestureRecognizer?
     var rotateRecognizer: UIRotationGestureRecognizer?

     override func viewDidLoad() {
          super.viewDidLoad()
          // Create gesture with target self(viewcontroller) and handler function.  
          self.panRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.handlePan(recognizer:)))
          self.pinchRecognizer = UIPinchGestureRecognizer(target: self, action: #selector(self.handlePinch(recognizer:)))
          self.rotateRecognizer = UIRotationGestureRecognizer(target: self, action: #selector(self.handleRotate(recognizer:)))
          //delegate gesture with UIGestureRecognizerDelegate
          pinchRecognizer?.delegate = self
          rotateRecognizer?.delegate = self
          panRecognizer?.delegate = self
          // than add gesture to imgView
          self.imgView.addGestureRecognizer(panRecognizer!)
          self.imgView.addGestureRecognizer(pinchRecognizer!)
          self.imgView.addGestureRecognizer(rotateRecognizer!)
     }

     // handle UIPanGestureRecognizer 
     @objc func handlePan(recognizer: UIPanGestureRecognizer) {    
          let gview = recognizer.view
          if recognizer.state == .began || recognizer.state == .changed {
               let translation = recognizer.translation(in: gview?.superview)
               gview?.center = CGPoint(x: (gview?.center.x)! + translation.x, y: (gview?.center.y)! + translation.y)
               recognizer.setTranslation(CGPoint.zero, in: gview?.superview)
          }
     }

     // handle UIPinchGestureRecognizer 
     @objc func handlePinch(recognizer: UIPinchGestureRecognizer) {
          if recognizer.state == .began || recognizer.state == .changed {
               recognizer.view?.transform = (recognizer.view?.transform.scaledBy(x: recognizer.scale, y: recognizer.scale))!
               recognizer.scale = 1.0
         }
     }   

     // handle UIRotationGestureRecognizer 
     @objc func handleRotate(recognizer: UIRotationGestureRecognizer) {
          if recognizer.state == .began || recognizer.state == .changed {
               recognizer.view?.transform = (recognizer.view?.transform.rotated(by: recognizer.rotation))!
               recognizer.rotation = 0.0
           }
     }

     // mark sure you override this function to make gestures work together 
     func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
         return true
     }

}

Qualquer pergunta, basta digitar para comentar. obrigado

Leang Socheat
fonte
3

Exemplo SWIFT 3

override func viewDidLoad() {

    self.backgroundImageView.addGestureRecognizer(
        UITapGestureRecognizer.init(target: self, action:#selector(didTapImageview(_:)))
    )

    self.backgroundImageView.isUserInteractionEnabled = true
}

func didTapImageview(_ sender: Any) {
    // do something
}

Nenhum representante do recongnizer de gestos ou outras implementações, quando necessário.

mourodrigo
fonte
2

Você também pode arrastar um reconhecedor de gestos para a visualização da imagem Storyboard. Em seguida, crie uma ação ctrl + dragpara o código.

zevij
fonte
1

Para o amante de Blocos, você pode usar ALActionBlocks para adicionar ação de gestos em bloco

__weak ALViewController *wSelf = self;
imageView.userInteractionEnabled = YES;
UITapGestureRecognizer *gr = [[UITapGestureRecognizer alloc] initWithBlock:^(UITapGestureRecognizer *weakGR) {
    NSLog(@"pan %@", NSStringFromCGPoint([weakGR locationInView:wSelf.view]));
}];
[self.imageView addGestureRecognizer:gr];
dimo hamdy
fonte