UIGestureRecognizer w UIImageView

179

Mam plik UIImageView, który chcę zmienić rozmiar i obracać itp.

Czy UIGestureRecognizermożna dodać do UIImageView?

Chciałbym dodać moduł rozpoznawania rotacji i szczypania, UIImageViewktóry zostanie utworzony w czasie wykonywania.

Jak dodać te urządzenia rozpoznające?

system
źródło

Odpowiedzi:

426

Sprawdź, czy userInteractionEnabledjest YESna UIImageView. Następnie możesz dodać rozpoznawanie gestów.

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
źródło
5
Nie, to tylko pokazuje, jak dodać rozpoznawanie gestów. Musisz dokonać rzeczywistego powiększenia / obrotu w manipulatorach gestów. Zobacz przykładową aplikację Touches_GestureRecognizers na temat sposobu powiększania / obracania.
77
+1 siedziałem tutaj od wieków, próbując dowiedzieć się, dlaczego moje gesty nie działają. „Sprawdź, czy UserInteractionEnabled ma TAK na UIImageView”. Dzięki!
Critter
1
To zdecydowanie sprawiło, że moja praca była łatwiejsza niż próba ustawienia limitów dla zestawu rozpoznawania dla ogólnego widoku. Dzięki!
Josh Kovach,
6
imageView.userInteractionEnabled = TAK; to jest klucz! Dziękuję Ci.
HamasN
3
userInteractionEnablednadal musi być ustawiony na TAK / prawda w Xcode 8 Objective-C / Swift
leanne
76

Tak, do UIImageView można dodać UIGestureRecognizer. Jak stwierdzono w drugiej odpowiedzi, bardzo ważne jest, aby pamiętać, aby umożliwić interakcję użytkownika w widoku obrazu poprzez ustawienie jego userInteractionEnabledwłaściwości na YES. UIImageView dziedziczy z UIView, którego właściwość interakcji użytkownika jest ustawiona YESdomyślnie, jednak właściwość interakcji użytkownika UIImageView jest ustawiona NOdomyślnie.

Z dokumentów UIImageView:

Nowe obiekty widoku obrazu są skonfigurowane tak, aby domyślnie ignorować zdarzenia użytkownika. Jeśli chcesz obsługiwać zdarzenia w niestandardowej podklasie UIImageView, musisz jawnie zmienić wartość właściwości userInteractionEnabled na YES po zainicjowaniu obiektu.

Tak czy inaczej, większość odpowiedzi. Oto przykład, jak utworzyć za UIImageViewpomocą a UIPinchGestureRecognizer, a UIRotationGestureRecognizeri a UIPanGestureRecognizer.

Po pierwsze, viewDidLoadlub inną wybraną metodą, utwórz widok obrazu, nadaj mu obraz, ramkę i włącz interakcję użytkownika. Następnie utwórz trzy gesty w następujący sposób. Pamiętaj, aby użyć ich właściwości delegowanej (najprawdopodobniej ustawionej na self). Będzie to konieczne, aby używać wielu gestów jednocześnie.

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

Oto trzy metody, które zostaną wywołane po wykryciu gestów w twoim widoku. Wewnątrz sprawdzimy aktualny stan gestu, a jeśli jest on w rozpoczęciu lub zmianie UIGestureRecognizerState, odczytamy właściwość skali / obrotu / tłumaczenia gestu, zastosujemy te dane do transformacji afinicznej, zastosujemy transformację afiniczną do obrazu widok, a następnie zresetuj skalę / obrót / tłumaczenie gestów.

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

Wreszcie, co bardzo ważne, musisz użyć metody UIGestureRecognizerDelegate , gestureRecognizer: shouldRecognizeSimultaneouslyWithGestureRecognizeraby umożliwić jednoczesne działanie gestów. Jeśli te trzy gesty są jedynymi trzema gestami, którym przypisano tę klasę jako delegata, możesz po prostu powrócić, YESjak pokazano poniżej. Jeśli jednak masz dodatkowe gesty, do których przypisano tę klasę jako ich delegata, może być konieczne dodanie logiki do tej metody, aby określić, który gest jest, przed umożliwieniem im wszystkim współpracy.

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

Nie zapomnij upewnić się, że twoja klasa jest zgodna z protokołem UIGestureRecognizerDelegate . Aby to zrobić, upewnij się, że interfejs wygląda mniej więcej tak:

@interface MyClass : MySuperClass <UIGestureRecognizerDelegate>

Jeśli wolisz sam bawić się kodem w działającym przykładowym projekcie, przykładowy projekt, który utworzyłem, zawierający ten kod, można znaleźć tutaj.

Mick MacCallum
źródło
1
To zdecydowanie najlepsza odpowiedź, jaką kiedykolwiek widziałem na stackoverflow.com, pełna szczegółowych, dobrze skomentowanych, a nawet zawiera kod źródłowy na git. Dzięki za to
Alejandro Luengo
1
Jasne, krok po kroku, niesamowite wyjaśnienie
Alvin,
1
Dziękuję, że to zrobiło na stronie lub dwóch, czego kilkadziesiąt samouczków przez lata Apple i inni nie zrobili. Uważam, że musi istnieć wiele innych rzeczy w iOS, które są możliwe, ale z powodu zaciemnienia i nieporozumień są dla nas stracone.
Zack Morris,
Świetna odpowiedź, najlepsza. Wielkie dzięki za cierpliwość.
Jorg B Jorge
13

Szybki 4.2

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

a po stuknięciu:

@objc func imageTapped(_ sender: UITapGestureRecognizer) {
   // do something when image tapped
   print("image tapped")
}
ayalcinkaya
źródło
11

Rozwiązanie Swift 2.0

W tej samej posiadłości tworzysz rozpoznawanie gestów dotykania, szczypania lub przeciągania. Poniżej przeprowadzę cię przez 4 kroki, aby uruchomić program rozpoznający.

4 kroki

1.) Dziedzicz UIGestureRecognizerDelegatepo dodaniu go do podpisu klasy.

class ViewController: UIViewController, UIGestureRecognizerDelegate {...}

2.) Kontroluj przeciąganie z obrazu do viewController, aby utworzyć IBOutlet:

@IBOutlet weak var tapView: UIImageView!

3.) W swoim viewDidLoad dodaj następujący kod:

// 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.) Utwórz funkcję, która zostanie wywołana po stuknięciu rozpoznawania gestów. (Możesz wykluczyć, = niljeśli wybierzesz).

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

Twój końcowy kod powinien wyglądać mniej więcej tak:

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
źródło
1
napisałem o tym blog tutaj: codebeaulieu.com/3/UIGestureRecognier-programatically
Dan Beaulieu
6

Właśnie to zrobiłem z swift4, dodając 3 gesty razem w jednym widoku

  1. UIPinchGestureRecognizer : Powiększ i pomniejsz widok.
  2. UIRotationGestureRecognizer : Obróć widok.
  3. UIPanGestureRecognizer : Przeciąganie widoku.

Oto mój przykładowy kod

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
     }

}

Wszelkie pytania, po prostu wpisz komentarz. Dziękuję Ci

Leang Socheat
źródło
3

Przykład 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
}

W razie potrzeby nie można delegować narzędzia do rozpoznawania gestów ani innych implementacji.

żałoba
źródło
2

Możesz także przeciągnąć rozpoznawanie gestów dotknij do widoku obrazu w Storyboard. Następnie utwórz akcję według ctrl + dragkodu.

zevij
źródło
1

Dla miłośnika bloków możesz użyć ALActionBlocks, aby dodać akcję gestów w bloku

__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
źródło