Bisakah Anda melampirkan UIGestureRecognizer ke beberapa tampilan?

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

Dalam kode di atas hanya ketukan view2yang dikenali. Jika saya mengomentari baris ketiga maka ketukan view1diakui. Jika saya benar dan Anda hanya dapat menggunakan pengukur gerakan satu kali, saya tidak yakin apakah ini bug atau hanya perlu dokumentasi lagi.

kubi
sumber

Jawaban:

334

A UIGestureRecognizerakan digunakan dengan satu tampilan. Saya setuju dokumentasinya jerawatan. Yang UIGestureRecognizermemiliki satu viewproperti memberikannya:

melihat

Tampilan pengenal isyarat terlampir. (hanya baca)

@property (nonatomik, hanya baca) Tampilan UIView *

Diskusi Anda melampirkan (atau menambahkan) pengenal isyarat ke objek UIView menggunakan metode addGestureRecognizer:.

TomSwift
sumber
11
Karena menambahkan pengenal isyarat ke tampilan terjadi saat runtime (vs. waktu kompilasi).
TomSwift
1
Saya mengerti, tetapi seperti mendeteksi yang mengatakan bahwa kami belum menggunakan variabel, XCode dapat mengatakan berdasarkan kode bahwa kami telah memberikan pengenal yang sama ke banyak tampilan dan dapat memperingatkan pembuat kode.
Zoltán Matók
1
Peringatan kompilator tentang beberapa tampilan yang menetapkan UITapGestureRecognizer yang sama adalah omong kosong, karena Anda mungkin ingin melakukan ini dengan sengaja, misalnya jika Anda ingin memindahkan pengukur gerakan tap di sekitar dari satu tampilan ke tampilan lainnya. Yang mengatakan, itu adalah batasan konyol bahwa pengenal isyarat tidak dapat digunakan pada banyak tampilan.
Erik van der Neut
1
iOS 9 sekarang memberlakukan satu tampilan per gesture recogniser, saya telah menggunakan metode pembangun antarmuka di bawah ini, tetapi sekarang saya mendapatkan pesan berikut ketika saya mencoba menggunakannya (beberapa detail dipotong untuk singkatnya): PERINGATAN: Pengenal gerakan (< UITapGestureRecognizer: .....>) disetel dalam storyboard / xib untuk ditambahkan ke lebih dari satu tampilan (-> <UIView:; frame = (0 44; 600 536); autoresize = RM + BM; gestureRecognizers = < NSArray ...:>; layer = <CALayer: ... >>) pada suatu waktu, ini tidak pernah diizinkan, dan sekarang diberlakukan. Dimulai dengan iOS 9.0 itu akan dimasukkan ke dalam tampilan pertama itu dimasukkan.
George Brown
Jika Anda menambahkan untuk melihat pada kedua kalinya, tampilan telah dilampirkan sebelum itu oleh pengenal ini semakin tidak diikat secara otomatis UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didPressed:)]; [self.view1 addGestureRecognizer:tapRecognizer]; [self.view2 addGestureRecognizer:tapRecognizer];Output view1 tidak memiliki larik pengenal isyarat; view2 telah mendapatkan larik pengenal isyarat
kokos8998
48

Saya mengatasinya dengan menggunakan di bawah ini.

for (UIButton *aButton in myButtons) {

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

}

Kemudian dalam metode handleLongPress saya, saya hanya menetapkan UIButton sama dengan tampilan pengenal gerakan dan bercabang apa yang saya lakukan berdasarkan tombol itu

- (void)handleLongPress:(UILongPressGestureRecognizer*)gesture {
    if ( gesture.state == UIGestureRecognizerStateEnded ) {
        UIButton *whichButton=(UIButton *)[gesture view];
        selectedButton=(UIButton *)[gesture view];
    ....
}
kwalker
sumber
1
Jawaban yang bagus. Terima kasih banyak. Ini bisa menjadi jawaban yang diterima jika pertanyaannya adalah "Bagaimana Anda melampirkan UIGestureRecognizer ke beberapa tampilan?"
D_D
7
Ini (atau sesuatu yang sangat dekat dengan ini) tidak bekerja untuk saya. Saya menambahkan beberapa tampilan ke pengenal gerakan ketuk di Interface Builder, dan menghubungkan pengenal ke suatu tindakan. Aksi dipanggil kapan saja tampilan terlampir disadap, tetapi gesture.view selalu merupakan tampilan terakhir yang dilampirkan.
Aneil Mallavarapu
Ini adalah jawaban yang sangat bagus dan juga sangat membantu dan setuju dengan @MicRO +1
Dilip
2
Aneil, itu karena Anda tidak membuat instance baru dari pengenal gerakan. Apa yang terjadi di loop dalam jawaban ini di sini adalah bahwa instance baru pengenal isyarat dibuat, masing-masing dengan hanya satu tampilan terlampir. Mereka semua dapat menunjuk ke penangan yang sama, di mana Anda kemudian memeriksa tampilan untuk melihat mana yang disentuh.
Erik van der Neut
1
Dapatkah orang lain mengkonfirmasi bahwa ini tidak lagi berfungsi dalam versi Obj-C / Swift saat ini?
Maxi Mus
18

Untuk Swift 3 jika ada yang membutuhkan ini: Berdasarkan Bhavik Rathod Jawaban di atas.

 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
sumber
3
itu pada dasarnya menciptakan beberapa gerakan untuk dua tampilan, masih aturan yang sama: setiap gerakan hanya memiliki satu pandangan untuk dilampirkan
Abdoelrhman
3
Tidak, fungsi membuat gerakan setiap kali namanya
Abdoelrhman
2
nama fungsinya salah. fungsi logis di sini adalah fungsi mendapatkan. jadi harus dinamai: getGestureRecognizekarena itulah fungsi ini
David Seek
Bekerja bagus untukku! Dan kode lebih bersih daripada membuat banyak variabel atau memasukkan seluruh kode untuk pembuatan di dalam addGestureRecognizer
Codenator81
11

Kita bisa melakukan sesuatu. Seperti ini, mudah dan sederhana

1) buat fungsi seperti di bawah ini di controller Anda (fungsi ini akan mengembalikan GestureRecognizer)

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

2) sekarang atur pengenal ini dalam banyak tampilan

[self.view1 addGestureRecognizer:[self setRecognizer]]; 
[self.view2 addGestureRecognizer:[self setRecognizer]];
Bhavik Rathod
sumber
Ini tidak berfungsi untuk saya ketika saya menggunakan dua label, bukan tampilan.
Mihir Oza
3
@Mihir Oza, itu tidak bisa bekerja untuk label UIL secara langsung. Karena label tidak masuk akal untuk interaksi pengguna. Jika Anda ingin menambahkan gerakan untuk label UIL tambahkan baris ini labelName..isUserInteractionEnabled = true di Swift. Kemudian tambahkan gerakan.
iOS
Sudah terlambat, aku sudah memperbaikinya. Tapi terima kasih untuk sarannya. Komentar Anda akan sangat membantu bagi pengguna tumpukan. Dihargai!
Mihir Oza
1
Saya kira garis setNumberOfTapsRequired:1itu tidak perlu
Naveed Abbas
9

Tidak, Anda tidak boleh melampirkan pengenal isyarat ke lebih dari satu tampilan.

Ada informasi eksplisit ini dalam dokumentasi Apple:

Pengenal Gerakan Tertempel pada Tampilan

Setiap pengenal isyarat dikaitkan dengan satu tampilan. Sebaliknya, sebuah tampilan dapat memiliki beberapa pengenal isyarat, karena satu tampilan mungkin merespons banyak gerakan berbeda. Agar pengenal gesture mengenali sentuhan yang terjadi dalam tampilan tertentu, Anda harus melampirkan pengenal gesture ke tampilan itu.

Panduan Penanganan Acara untuk iOS - Pengenalan Gerakan Apple Developer Library

Sementara yang lain menyebutkan mereka mungkin bekerja dalam beberapa kasus itu jelas bertentangan dengan dokumentasi dan dapat berubah dalam versi iOS apa pun di masa depan.

Yang dapat Anda lakukan adalah menambahkan recogniser gerakan terpisah ke pandangan yang ingin Anda pantau dan mereka dapat berbagi aksi bersama.

Joseph Lord
sumber
4

Nah, jika seseorang tidak ingin kode untuk menambahkan tampilan gerakan untuk beberapa tombol seperti kwalker telah menjawab di atas, dan ingin melakukannya melalui Interface Builder ini dapat membantu Anda.

1) Anda dapat menambahkan Long Tekan gesture Recognizer dari Object Library seperti Anda menambahkan objek lain seperti UIButtons dan UILabels.

masukkan deskripsi gambar di sini Awalnya yang saya gunakan adalah saya hanya mengambil satu

2) Mengatur outlet referensi ke UIButtondan mengirim tindakan dengan Pemilik File.

masukkan deskripsi gambar di sini

Catatan: Jika Anda memiliki beberapa UIButton atau objek lain, Anda perlu pengenal isyarat terpisah untuk masing-masingnya. Untuk detail lebih lanjut, silakan merujuk ke pertanyaan saya ini. Tag UIButton salah pada pengenal gesture tekan lama

rohan-patel
sumber
Sangat mudah untuk mengikat lebih dari satu UIView ke guesture recognitionizer menggunakan IB. Pertanyaannya adalah tentang pembuatan kode.
AlexeyVMP
3

jika Anda telah memperbaiki tampilan, saya sarankan Anda melakukan sesuatu seperti ini

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

cara itu akan mengurangi beberapa variabel tidak berguna yang berbeda

Raynaldio Limarga
sumber
3

Anda dapat membuat ekstensi generik pada tampilan untuk menambahkan pengenal isyarat dengan mudah. Ini hanya contoh tetapi bisa terlihat seperti ini

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

}

Untuk menambahkan pengenal 2 ketuk pada tampilan yang Anda sebut saja:

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

Anda juga dapat dengan mudah menambahkan pengenal gesek

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

dan seterusnya. Ingat saja bahwa target harus ditautkan ke pemilih.

Martin
sumber
2

Ganti kelas dengan ' <UIScrollViewDelegate>'

Dan gunakan metode ini di kelas .m:

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

Metode ini akan membantu Anda untuk mengaktifkan beberapa gesekan pada satu tampilan ..

AnkitRox
sumber
2

Bagaimana dengan menulis ulang (buat ulang) GestureRecognize Anda setiap kali Anda menambahkan pengenal isyarat yang menunjuk ke fungsi yang sama. Dalam kasus di bawah ini berfungsi. Saya menggunakan 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
sumber
-6

Anda dapat melakukannya menggunakan kode ini pandangan saya yang merupakan tampilan gambar di 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
sumber
1
Anda membuat beberapa pengenal isyarat; pertanyaan awal saya adalah tentang menggunakan kembali alat pengenal isyarat tunggal, yang tidak dapat Anda lakukan.
kubi
1
Apa gunanya menambahkan 500semua tag tampilan Anda dan kemudian mengurangi 500? Mengapa tidak memulai tag Anda di 1(atau bahkan 0) saja 501?
ma11hew28
@MattDiPasquale, Tidak masalah jika Anda ingin memulai dengan 1yang baru saja saya salin kode ini dari aplikasi saya di mana saya memberikannya 501. Tapi ya jangan memberikan 0bcoz saya telah membaca di suatu tempat yang selalu menunjukkan pandangan orang tua sehingga akan membuat komplikasi, Percayalah, saya telah menghadapinya.
Dilip
Teks kunci dalam dokumentasi adalah "Tampilan membuat referensi yang kuat ke pengenal gesture." yang berarti bahwa pandangan memiliki gerakan itu. Gerakan itu hanya dapat memiliki satu pemilik. Lihat tautan
Phantom59