Trình nhận dạng UIGesture trên UIImageView


179

Tôi có một UIImageView, mà tôi muốn có thể thay đổi kích thước và xoay, v.v.

Có thể UIGestureRecognizerđược thêm vào UIImageView?

Tôi muốn thêm một công cụ nhận dạng xoay và chụm vào một UIImageViewcái sẽ được tạo khi chạy.

Làm thế nào để thêm những nhận dạng này?

Câu trả lời:


426

Kiểm tra đó userInteractionEnabledYEStrên UIImageView. Sau đó, bạn có thể thêm một nhận dạng cử chỉ.

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

5
Không, điều này chỉ cho thấy làm thế nào để thêm các nhận dạng cử chỉ. Bạn phải thực hiện thu phóng / xoay thực tế trong trình xử lý cử chỉ. Xem ứng dụng mẫu Touches_GestureRecognors về cách thực hiện thu phóng / xoay.

77
+1 ngồi ở đây trong nhiều năm cố gắng tìm hiểu lý do tại sao cử chỉ của tôi không hoạt động .. "Kiểm tra xem userInteractionEnables có CÓ trên UIImageView không." Cảm ơn!
Critter

1
Điều này chắc chắn làm cho công việc của tôi dễ dàng hơn là cố gắng đặt giới hạn cho bộ nhận dạng được đặt thành chế độ xem tổng thể. Cảm ơn!
Josh Kovach

6
imageView.userInteractionEnables = CÓ; đây là chìa khóa Cảm ơn bạn.
HamasN

3
userInteractionEnabledvẫn phải được đặt thành CÓ / đúng trong Xcode 8 Objective-C / Swift
leanne

76

Có, một UIGestureRecognizer có thể được thêm vào UIImageView. Như đã nêu trong câu trả lời khác, điều rất quan trọng cần nhớ là cho phép người dùng tương tác trên chế độ xem hình ảnh bằng cách đặt thuộc tính của nó userInteractionEnabledthành YES. UIImageView kế thừa từ UIView, có thuộc tính tương tác người dùng được đặt thành YESmặc định, tuy nhiên, thuộc tính tương tác người dùng của UIImageView được đặt thành NOmặc định.

Từ các tài liệu UIImageView:

Các đối tượng xem hình ảnh mới được cấu hình để bỏ qua các sự kiện người dùng theo mặc định. Nếu bạn muốn xử lý các sự kiện trong một lớp con tùy chỉnh của UIImageView, bạn phải thay đổi rõ ràng giá trị của thuộc tính userInteractionEnables thành CÓ sau khi khởi tạo đối tượng.

Dù sao, trên phần lớn của câu trả lời. Đây là một ví dụ về cách tạo a UIImageViewvới a UIPinchGestureRecognizer, a UIRotationGestureRecognizervà a UIPanGestureRecognizer.

Đầu tiên, trong viewDidLoadhoặc một phương pháp khác bạn chọn, tạo chế độ xem hình ảnh, cung cấp cho nó hình ảnh, khung và cho phép tương tác người dùng của nó. Sau đó tạo ba cử chỉ như sau. Hãy chắc chắn sử dụng tài sản đại biểu của họ (rất có thể được đặt thành tự). Điều này sẽ được yêu cầu để sử dụng nhiều cử chỉ cùng một lúc.

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

Dưới đây là ba phương thức sẽ được gọi khi các cử chỉ trên chế độ xem của bạn được phát hiện. Bên trong chúng, chúng tôi sẽ kiểm tra trạng thái hiện tại của cử chỉ và nếu nó ở trạng thái bắt đầu hoặc thay đổi, UIGestureRecognizerStatechúng tôi sẽ đọc thuộc tính tỷ lệ / xoay / dịch của cử chỉ, áp dụng dữ liệu đó vào một biến đổi affine, áp dụng biến đổi affine cho hình ảnh xem, và sau đó thiết lập lại tỷ lệ cử chỉ / xoay / dịch.

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

Cuối cùng và rất quan trọng, bạn sẽ cần sử dụng phương pháp UIGestureRecognizerDelegategestureRecognizer: shouldRecognizeSimultaneouslyWithGestureRecognizer để cho phép các cử chỉ hoạt động cùng một lúc. Nếu ba cử chỉ này là ba cử chỉ duy nhất có lớp này được chỉ định làm đại biểu của chúng, thì bạn có thể chỉ cần quay lại YESnhư hình dưới đây. Tuy nhiên, nếu bạn có các cử chỉ bổ sung có lớp này được chỉ định làm đại biểu của chúng, bạn có thể cần thêm logic vào phương thức này để xác định cử chỉ nào là trước khi cho phép tất cả chúng hoạt động cùng nhau.

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

Đừng quên đảm bảo rằng lớp của bạn tuân thủ giao thức UIGestureRecognizerDelegate . Để làm như vậy, hãy chắc chắn rằng giao diện của bạn trông giống như thế này:

@interface MyClass : MySuperClass <UIGestureRecognizerDelegate>

Nếu bạn muốn tự chơi với mã trong một dự án mẫu đang hoạt động, dự án mẫu tôi đã tạo có chứa mã này có thể được tìm thấy ở đây.


1
Đây là câu trả lời hay nhất tôi từng thấy trong stackoverflow.com, đầy đủ chi tiết, được bình luận tốt và thậm chí bao gồm cả mã nguồn trên git. Cảm ơn vì điều đó
Alejandro Luengo

1
Rõ ràng, từng bước, giải thích tuyệt vời
Alvin

1
Cảm ơn bạn, điều đó đã làm trong một hoặc hai trang mà hàng tá hướng dẫn trong nhiều năm qua của Apple và những người khác đã không làm được. Tôi cảm thấy rằng phải có nhiều thứ khác trong iOS là có thể, nhưng do sự xáo trộn và hiểu lầm, chúng đã bị mất đối với chúng tôi.
Zack Morris

Câu trả lời tuyệt vời, tốt nhất. Cảm ơn rất nhiều vì sự kiên nhẫn của bạn.
Jorg B Jorge

13

Swift 4.2

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

và khi gõ:

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

11

Giải pháp Swift 2.0

Bạn tạo một thao tác chạm, véo hoặc vuốt nhận dạng cử chỉ trong cùng một trang viên. Dưới đây tôi sẽ hướng dẫn bạn 4 bước để nhận biết và chạy.

4 bước

1.) Kế thừa từ UIGestureRecognizerDelegatebằng cách thêm nó vào chữ ký lớp của bạn.

class ViewController: UIViewController, UIGestureRecognizerDelegate {...}

2.) Điều khiển kéo từ hình ảnh của bạn đến viewControll để tạo IBOutlet:

@IBOutlet weak var tapView: UIImageView!

3.) Trong viewDidLoad của bạn thêm mã sau đây:

// 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.) Tạo chức năng sẽ được gọi khi nhận dạng cử chỉ của bạn được gõ. (Bạn có thể loại trừ = nilnếu bạn chọn).

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

Mã cuối cùng của bạn sẽ trông giống như thế này:

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

1
tôi đã viết một blog về điều này ở đây: codebeaulieu.com/3/UIGestureRecognier-programatically
Dan Beaulieu

6

Tôi vừa thực hiện điều này với swift4 bằng cách thêm 3 cử chỉ lại với nhau trong một lần xem

  1. UIPinchGestureRecognizer : Phóng to và thu nhỏ chế độ xem.
  2. UIRotationGestureRecognizer : Xoay chế độ xem.
  3. UIPanGestureRecognizer : Kéo chế độ xem.

Đây là mã mẫu của tôi

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
     }

}

Bất kỳ câu hỏi, chỉ cần gõ để bình luận. cảm ơn bạn


3

Ví dụ 3

override func viewDidLoad() {

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

    self.backgroundImageView.isUserInteractionEnabled = true
}

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

Không có đại biểu recongnizer cử chỉ hoặc thực hiện khác khi cần thiết.


2

Bạn cũng có thể kéo một trình nhận dạng cử chỉ nhấn vào chế độ xem hình ảnh trong Storyboard. Sau đó tạo một hành động bằng ctrl + dragmã.


1

Đối với người yêu khối, bạn có thể sử dụng ALActionBlocks để thêm hành động của cử chỉ trong khối

__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];
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.