Bagaimana cara menambahkan acara sentuh ke UIView?


280

Bagaimana cara menambahkan acara sentuh ke UIView?
Saya coba:

UIView *headerView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, nextY)] autorelease];
[headerView addTarget:self action:@selector(myEvent:) forControlEvents:UIControlEventTouchDown];
// ERROR MESSAGE: UIView may not respond to '-addTarget:action:forControlEvents:'

Saya tidak ingin membuat subclass dan menimpa

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

Untuk cepat Anda bisa mendapatkannya dari sini: stackoverflow.com/questions/28675209/…
Mr.Javed Multani

Jawaban:


578

Di iOS 3.2 dan lebih tinggi, Anda dapat menggunakan pengenal isyarat. Misalnya, ini adalah cara Anda menangani acara tap:

//The setup code (in viewDidLoad in your view controller)
UITapGestureRecognizer *singleFingerTap = 
  [[UITapGestureRecognizer alloc] initWithTarget:self 
                                          action:@selector(handleSingleTap:)];
[self.view addGestureRecognizer:singleFingerTap];

//The event handling method
- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer
{
  CGPoint location = [recognizer locationInView:[recognizer.view superview]];

  //Do stuff here...
}

Ada banyak gerakan bawaan juga. Lihat dokumen untuk penanganan acara iOS dan UIGestureRecognizer. Saya juga punya banyak kode contoh di github yang mungkin bisa membantu.


Tapi itu menimpa sentuhan sentuhan aksi tampilan. ¿Apakah mungkin untuk melakukan aksi sentuh sentuh pada tampilan? Sesuatu seperti [sentuhan super Mulai]? ...
M Penades

2
Apa yang dilakukan garis CGPoint?
zakdances

2
@ teman Anda CGPointmewakili lokasi ketukan di tampilan tampilan yang disadap. Anda dapat menggunakan titik ini untuk memindahkan tampilan yang diketuk (atau tampilan saudara) ke lokasi yang diketuk. Ini lebih bermanfaat dalam penangan UIPanGestureRecognizeruntuk menyeret tampilan di sekitar layar.
Nathan Eror

5
jawaban singkat yang bagus, terima kasih. tapi dia, bukankah lebih baik jika ini sedikit lebih mudah ?! :)
natbro

Ini tidak terlalu buruk, tapi saya berharap ada API berbasis blok seperti github.com/neror/ftutils/blob/master/Headers/FTUtils/… . Xcode 4 memang memiliki dukungan untuk menambah / mengkonfigurasi pengenal gesture di Interface Builder juga.
Nathan Eror

126

Pengenal Gerakan

Ada sejumlah peristiwa sentuh (atau gerakan) yang umum digunakan yang dapat Anda beri tahu saat Anda menambahkan Gesture Recognizer ke tampilan Anda. Mereka mengikuti jenis gerakan didukung secara default:

  • UITapGestureRecognizer Ketuk (menyentuh layar sebentar satu atau lebih kali)
  • UILongPressGestureRecognizer Sentuhan panjang (menyentuh layar untuk waktu yang lama)
  • UIPanGestureRecognizer Geser (gerakkan jari Anda melintasi layar)
  • UISwipeGestureRecognizer Geser (gerakkan jari dengan cepat)
  • UIPinchGestureRecognizer Jepit (gerakkan dua jari bersamaan atau terpisah - biasanya untuk memperbesar)
  • UIRotationGestureRecognizer Putar (menggerakkan dua jari dalam arah melingkar)

Selain itu, Anda juga dapat membuat pengenal isyarat khusus sendiri.

Menambahkan Gerakan di Pembuat Antarmuka

Seret pengenal isyarat dari pustaka objek ke tampilan Anda.

masukkan deskripsi gambar di sini

Kendalikan kontrol dari gerakan di Outline Dokumen ke kode Pengontrol Tampilan Anda untuk membuat Outlet dan Tindakan.

masukkan deskripsi gambar di sini

Ini harus ditetapkan secara default, tetapi juga memastikan bahwa Tindakan Pengguna Diaktifkan disetel ke true untuk tampilan Anda.

masukkan deskripsi gambar di sini

Menambahkan Gerakan secara Programatis

Untuk menambahkan gerakan secara terprogram, Anda (1) membuat pengenal gerakan, (2) menambahkannya ke tampilan, dan (3) membuat metode yang disebut ketika gerakan dikenali.

import UIKit
class ViewController: UIViewController {

    @IBOutlet weak var myView: UIView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 1. create a gesture recognizer (tap gesture)
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(sender:)))
        
        // 2. add the gesture recognizer to a view
        myView.addGestureRecognizer(tapGesture)
    }
    
    // 3. this method is called when a tap is recognized
    @objc func handleTap(sender: UITapGestureRecognizer) {
        print("tap")
    }
}

Catatan

  • The senderparameter opsional. Jika Anda tidak perlu referensi ke isyarat maka Anda dapat meninggalkannya. Jika Anda melakukannya, hapus (sender:)nama metode tindakan setelah.
  • Penamaan handleTapmetode ini sewenang-wenang. Beri nama apa pun yang ingin Anda gunakan .action: #selector(someMethodName(sender:))

Lebih banyak contoh

Anda dapat mempelajari pengenal isyarat yang saya tambahkan ke tampilan ini untuk melihat cara kerjanya.

masukkan deskripsi gambar di sini

Berikut adalah kode untuk proyek itu:

import UIKit
class ViewController: UIViewController {
    
    @IBOutlet weak var tapView: UIView!
    @IBOutlet weak var doubleTapView: UIView!
    @IBOutlet weak var longPressView: UIView!
    @IBOutlet weak var panView: UIView!
    @IBOutlet weak var swipeView: UIView!
    @IBOutlet weak var pinchView: UIView!
    @IBOutlet weak var rotateView: UIView!
    @IBOutlet weak var label: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // Tap
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap))
        tapView.addGestureRecognizer(tapGesture)
        
        // Double Tap
        let doubleTapGesture = UITapGestureRecognizer(target: self, action: #selector(handleDoubleTap))
        doubleTapGesture.numberOfTapsRequired = 2
        doubleTapView.addGestureRecognizer(doubleTapGesture)
        
        // Long Press
        let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress(gesture:)))
        longPressView.addGestureRecognizer(longPressGesture)
        
        // Pan
        let panGesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan(gesture:)))
        panView.addGestureRecognizer(panGesture)
        
        // Swipe (right and left)
        let swipeRightGesture = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe(gesture:)))
        let swipeLeftGesture = UISwipeGestureRecognizer(target: self, action: #selector(handleSwipe(gesture:)))
        swipeRightGesture.direction = UISwipeGestureRecognizerDirection.right
        swipeLeftGesture.direction = UISwipeGestureRecognizerDirection.left
        swipeView.addGestureRecognizer(swipeRightGesture)
        swipeView.addGestureRecognizer(swipeLeftGesture)
        
        // Pinch
        let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(handlePinch(gesture:)))
        pinchView.addGestureRecognizer(pinchGesture)
        
        // Rotate
        let rotateGesture = UIRotationGestureRecognizer(target: self, action: #selector(handleRotate(gesture:)))
        rotateView.addGestureRecognizer(rotateGesture)
        
    }
    
    // Tap action
    @objc func handleTap() {
        label.text = "Tap recognized"
        
        // example task: change background color
        if tapView.backgroundColor == UIColor.blue {
            tapView.backgroundColor = UIColor.red
        } else {
            tapView.backgroundColor = UIColor.blue
        }
        
    }
    
    // Double tap action
    @objc func handleDoubleTap() {
        label.text = "Double tap recognized"
        
        // example task: change background color
        if doubleTapView.backgroundColor == UIColor.yellow {
            doubleTapView.backgroundColor = UIColor.green
        } else {
            doubleTapView.backgroundColor = UIColor.yellow
        }
    }
    
    // Long press action
    @objc func handleLongPress(gesture: UILongPressGestureRecognizer) {
        label.text = "Long press recognized"
        
        // example task: show an alert
        if gesture.state == UIGestureRecognizerState.began {
            let alert = UIAlertController(title: "Long Press", message: "Can I help you?", preferredStyle: UIAlertControllerStyle.alert)
            alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil))
            self.present(alert, animated: true, completion: nil)
        }
    }
    
    // Pan action
    @objc func handlePan(gesture: UIPanGestureRecognizer) {
        label.text = "Pan recognized"
        
        // example task: drag view
        let location = gesture.location(in: view) // root view
        panView.center = location
    }
    
    // Swipe action
    @objc func handleSwipe(gesture: UISwipeGestureRecognizer) {
        label.text = "Swipe recognized"
        
        // example task: animate view off screen
        let originalLocation = swipeView.center
        if gesture.direction == UISwipeGestureRecognizerDirection.right {
            UIView.animate(withDuration: 0.5, animations: {
                self.swipeView.center.x += self.view.bounds.width
            }, completion: { (value: Bool) in
                self.swipeView.center = originalLocation
            })
        } else if gesture.direction == UISwipeGestureRecognizerDirection.left {
            UIView.animate(withDuration: 0.5, animations: {
                self.swipeView.center.x -= self.view.bounds.width
            }, completion: { (value: Bool) in
                self.swipeView.center = originalLocation
            })
        }
    }
    
    // Pinch action
    @objc func handlePinch(gesture: UIPinchGestureRecognizer) {
        label.text = "Pinch recognized"
        
        if gesture.state == UIGestureRecognizerState.changed {
            let transform = CGAffineTransform(scaleX: gesture.scale, y: gesture.scale)
            pinchView.transform = transform
        }
    }
    
    // Rotate action
    @objc func handleRotate(gesture: UIRotationGestureRecognizer) {
        label.text = "Rotate recognized"
        
        if gesture.state == UIGestureRecognizerState.changed {
            let transform = CGAffineTransform(rotationAngle: gesture.rotation)
            rotateView.transform = transform
        }
    }
}

Catatan

  • Anda dapat menambahkan beberapa pengenal isyarat ke satu tampilan. Demi kesederhanaan, saya tidak melakukan itu (kecuali untuk gerakan gesek). Jika Anda perlu untuk proyek Anda, Anda harus membaca dokumentasi gesture recognition . Ini cukup dimengerti dan bermanfaat.
  • Masalah yang diketahui dengan contoh saya di atas: (1) Tampilan pan me-reset frame-nya pada acara gesture berikutnya. (2) Tampilan gesek berasal dari arah yang salah pada gesekan pertama. (Bug-bug ini dalam contoh saya seharusnya tidak memengaruhi pemahaman Anda tentang cara kerja Pengenal Gerakan.)

2
Jawaban Anda sangat bagus dan bermanfaat dengan deskripsi terperinci. Dan itulah mengapa saya memilih Anda menjawab juga. Tetapi Anda baru saja melewatkan satu instruksi yang menurut saya harus Anda masukkan dalam jawaban Anda seperti yang telah Anda jelaskan secara terperinci. Instruksi itu adalah tentang menyetel "<yourView> .EnableUserInteraction = TRUE". Saya harap Anda setuju dengan saya.
Er. Vihar

3
Untuk membuat ini berhasil, UIViewAnda juga perlu menambahkan:self.isUserInteractionEnabled = true;
neiker

52

Saya pikir Anda cukup menggunakan

UIControl *headerView = ...
[headerView addTarget:self action:@selector(myEvent:) forControlEvents:UIControlEventTouchDown];

maksud saya headerView meluas dari UIControl.


7
Ini jawaban yang lebih baik. UITapGestureRecognizerbukan pengganti UIControlEventTouchDown. A Tapbiasanya terdiri dari UIControlEventTouchDowndan UIControlEventTouchUpInside.
ohho

62
A UIViewbukan a UIControldan dengan demikian tidak memiliki akses ke addTarget:action:forControlEvents:.
RobertJoseph

9
Perhatikan juga bahwa UIControl mewarisi dari UIView. Untuk tujuan saya semua yang harus saya lakukan adalah beralih sederhana dari tipe subclass.
pretzels1337

1
Anda dapat mengatur kelasnya ke UIControl @RobertJoseph .. Buka file xib dan atur kelas Lihat Kustom ke UIControl. sekarang Anda dapat menangani acara di dalamnya ..
Zar E Ahmer

2
Jadi mengapa ini solusi yang lebih baik lagi karena saya mengubah warisan hanya untuk menangani keran?
Anthony Glyadchenko

21

Swift 3 & Swift 4

import UIKit

extension UIView {
  func addTapGesture(tapNumber: Int, target: Any, action: Selector) {
    let tap = UITapGestureRecognizer(target: target, action: action)
    tap.numberOfTapsRequired = tapNumber
    addGestureRecognizer(tap)
    isUserInteractionEnabled = true
  }
}

Menggunakan

yourView.addTapGesture(tapNumber: 1, target: self, action: #selector(yourMethod))

Terima kasih. Bagus sekali!
Mikrasya

1
Suka ini! Menambahkan ke semua proyek;)
budidino

17

Berdasarkan jawaban yang diterima Anda dapat mendefinisikan makro:

#define handle_tap(view, delegate, selector) do {\
    view.userInteractionEnabled = YES;\
    [view addGestureRecognizer: [[UITapGestureRecognizer alloc] initWithTarget:delegate action:selector]];\
} while(0)

Makro ini menggunakan ARC, jadi tidak ada releasepanggilan.

Contoh penggunaan makro:

handle_tap(userpic, self, @selector(onTapUserpic:));

4
Jika Anda membuat tampilan di storyboard, jangan lupa untuk mengaktifkan opsi "interaksi pengguna yang diaktifkan".
david

di mana kita harus mendefinisikan makro dalam .h atau .m dan apa yang harus menjadi nama parameter. maksud saya #define handle_tap (tampilan UIView, delegasi delegasi, pemilih SEL) lakukan ..
Zar E Ahmer

8

Anda dapat mencapai ini dengan menambahkan Gesture Recogniser dalam kode Anda.

Langkah 1: ViewController.m:

// Declare the Gesture.
UITapGestureRecognizer *gesRecognizer = [[UITapGestureRecognizer alloc] 
                                          initWithTarget:self 
                                          action:@selector(handleTap:)];
gesRecognizer.delegate = self;

// Add Gesture to your view.
[yourView addGestureRecognizer:gesRecognizer]; 

Langkah 2: ViewController.m:

// Declare the Gesture Recogniser handler method.
- (void)handleTap:(UITapGestureRecognizer *)gestureRecognizer{
   NSLog(@"Tapped");
}

CATATAN: di sini yourView dalam kasus saya adalah @property (strong, nonatomic) IBOutlet UIView *localView;

Sunting : * localView adalah kotak putih di Main.storyboard dari bawah

masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini


saya memiliki beberapa tampilan sehingga dapatkah id pengirim ??
Moin Shirazi

Anda harus pergi ke subview bagian dalam, lalu Anda dapat mengirim pengirim .--------- untuk (tampilan UIView * di self.topicScrollView.subviews) {// Masuk ke dalam superview jika ([view isKindOfClass: [Kelas UIButton]]) {// Pergi ke tampilan khusus itu // Di sini Anda telah mencapai titik itu. }}
Annu

8

Di Swift 4.2 dan Xcode 10

Gunakan UITapGestureRecognizer untuk menambahkan acara sentuh

//Add tap gesture to your view
let tap = UITapGestureRecognizer(target: self, action: #selector(handleGesture))
yourView.addGestureRecognizer(tap)

// GestureRecognizer
@objc func handleGesture(gesture: UITapGestureRecognizer) -> Void {
//Write your code here
}

Jika Anda ingin menggunakan SharedClass

//This is my shared class
import UIKit

class SharedClass: NSObject {

    static let sharedInstance = SharedClass()

    //Tap gesture function
    func addTapGesture(view: UIView, target: Any, action: Selector) {
        let tap = UITapGestureRecognizer(target: target, action: action)
        view.addGestureRecognizer(tap)
    }
} 

Saya memiliki 3 tampilan di ViewController saya bernama view1, view2 dan view3.

override func viewDidLoad() {
    super.viewDidLoad()
    //Add gestures to your views
    SharedClass.sharedInstance.addTapGesture(view: view1, target: self, action: #selector(handleGesture))
    SharedClass.sharedInstance.addTapGesture(view: view2, target: self, action: #selector(handleGesture))
    SharedClass.sharedInstance.addTapGesture(view: view3, target: self, action: #selector(handleGesture2))

}

// GestureRecognizer
@objc func handleGesture(gesture: UITapGestureRecognizer) -> Void {
    print("printed 1&2...")
}
// GestureRecognizer
@objc func handleGesture2(gesture: UITapGestureRecognizer) -> Void {
    print("printed3...")
}

6

Inilah versi Swift:

// MARK: Gesture Extensions
extension UIView {

    func addTapGesture(#tapNumber: Int, target: AnyObject, action: Selector) {
        let tap = UITapGestureRecognizer (target: target, action: action)
        tap.numberOfTapsRequired = tapNumber
        addGestureRecognizer(tap)
        userInteractionEnabled = true
    }

    func addTapGesture(#tapNumber: Int, action: ((UITapGestureRecognizer)->())?) {
        let tap = BlockTap (tapCount: tapNumber, fingerCount: 1, action: action)
        addGestureRecognizer(tap)
        userInteractionEnabled = true
    }
}

apa BlockTap?
He Yifei 何 一 非

1
Oh man, lupakan bagian itu. Ini adalah fungsi khusus. Di sini: github.com/goktugyil/EZSwiftExtensions/blob/master/Sources/…
Esqarrouth

5

Swift 3:

let tapGestureRecognizer: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTapGestureRecognizer(_:)))
view.addGestureRecognizer(tapGestureRecognizer)

func handleTapGestureRecognizer(_ gestureRecognizer: UITapGestureRecognizer) {

}

1

Tampaknya cukup sederhana hari ini. Ini adalah versi Swift.

let tap = UITapGestureRecognizer(target: self, action: #selector(viewTapped))
    view.addGestureRecognizer(tap)

@objc func viewTapped(recognizer: UIGestureRecognizer)
{
    //Do what you need to do!
}

0

Ini adalah ios tapgesture; Pertama, Anda perlu membuat tindakan untuk GestureRecognizer setelah menulis kode di bawah ini di bawah tindakan seperti yang ditunjukkan di bawah ini

- (IBAction)tapgesture:(id)sender

{


[_password resignFirstResponder];


[_username resignFirstResponder];

NSLog(@" TapGestureRecognizer  tapped");

}

0

Cara lain adalah menambahkan tombol transparan ke tampilan

UIButton *b = [UIButton buttonWithType:UIButtonTypeCustom];
b.frame = CGRectMake(0, 0, headerView.width, headerView.height);
[headerView addSubview:b];
[b addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchDown];

Dan kemudian, menangani klik:

- (void)buttonClicked:(id)sender
{}

0

Buat pengenal isyarat (subkelas), yang akan mengimplementasikan acara sentuh, seperti touchesBegan. Anda dapat menambahkannya ke tampilan setelah itu.

Dengan cara ini Anda akan menggunakan komposisi alih-alih subklas (yang merupakan permintaan).


0

Mengapa kalian tidak mencoba SSEventListener ?

Anda tidak perlu membuat pengenal isyarat dan memisahkan logika Anda dengan metode lain. SSEventListenermendukung pengaturan blok pendengar pada tampilan untuk mendengarkan gerakan ketukan tunggal, gerakan ketuk ganda dan gerakan ketuk N jika Anda suka, dan gerakan tekan lama. Menyetel pendengar gerakan ketukan tunggal menjadi seperti ini:

[view ss_addTapViewEventListener:^(UITapGestureRecognizer *recognizer) { ... } numberOfTapsRequired:1];


0

Tujuan-C:

UIControl *headerView = [[UIControl alloc] initWithFrame:CGRectMake(0, 0, tableView.bounds.size.width, nextY)];
[headerView addTarget:self action:@selector(myEvent:) forControlEvents:UIControlEventTouchDown];

Cepat:

let headerView = UIControl(frame: CGRect(x: 0, y: 0, width: tableView.bounds.size.width, height: nextY))
headerView.addTarget(self, action: #selector(myEvent(_:)), for: .touchDown)

Pertanyaannya adalah:

Bagaimana cara menambahkan acara sentuh ke UIView?

Itu tidak meminta acara tap .

Secara khusus OP ingin mengimplementasikan UIControlEventTouchDown

Beralih UIViewke UIControladalah jawaban yang tepat di sini karena Gesture Recogniserstidak tahu apa-apa tentang .touchDown, .touchUpInside,.touchUpOutside dll

Selain itu, UIControl mewarisi dari UIView sehingga Anda tidak kehilangan fungsionalitas apa pun.

Jika semua yang Anda inginkan adalah sebuah ketukan, maka Anda dapat menggunakan Pengenal Gerakan. Tetapi jika Anda ingin kontrol yang lebih baik, seperti pertanyaan ini, Anda perlu UIControl.

https://developer.apple.com/documentation/uikit/uicontrol?language=objc https://developer.apple.com/documentation/uikit/uigesturerecognizer?language=objc

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.