Apakah ada cara sederhana untuk mengizinkan interaksi dengan tombol di UIView yang terletak di bawah UIView lain - di mana tidak ada objek aktual dari UIView atas di atas tombol?
Misalnya, saat ini saya memiliki UIView (A) dengan objek di bagian atas dan objek di bagian bawah layar dan tidak ada di tengah. Ini berada di atas UIView lain yang memiliki tombol di tengah (B). Namun, sepertinya saya tidak dapat berinteraksi dengan tombol di tengah B.
Saya dapat melihat tombol di B - Saya telah menyetel latar belakang A menjadi clearColor - tetapi tombol di B tampaknya tidak menerima sentuhan meskipun pada kenyataannya tidak ada objek dari A di atas tombol tersebut.
EDIT - Saya masih ingin dapat berinteraksi dengan objek di UIView atas
Tentunya ada cara sederhana untuk melakukan ini?
sumber
UIButton
yang berada di bawah semi transparanUIView
sedangkan bagian non transparanUIView
masih akan merespons peristiwa sentuh.Jawaban:
Anda harus membuat subclass UIView untuk tampilan teratas Anda dan mengganti metode berikut:
Anda juga dapat melihat metode hitTest: event:.
sumber
return
pernyataan itu, tetapireturn CGRectContainsPoint(eachSubview.frame, point)
berhasil untuk saya. Jawaban yang sangat membantu sebaliknyaMIDDLE_Y1<=y<=MIDDLE_Y2
area tersebut.Meskipun banyak dari jawaban di sini akan berfungsi, saya sedikit terkejut melihat bahwa jawaban yang paling nyaman, umum, dan sangat mudah belum diberikan di sini. @ Ash paling dekat, kecuali ada sesuatu yang aneh terjadi dengan mengembalikan superview ... jangan lakukan itu.
Jawaban ini diambil dari jawaban yang saya berikan untuk pertanyaan serupa, di sini .
[super hitTest:point withEvent:event]
akan mengembalikan tampilan terdalam dalam hierarki tampilan yang disentuh. JikahitView == self
(yaitu, jika tidak ada subview di bawah titik sentuh), kembalinil
, tentukan bahwa tampilan ini tidak boleh menerima sentuhan. Cara kerja rantai responden berarti bahwa hierarki tampilan di atas titik ini akan terus dilintasi hingga ditemukan tampilan yang akan merespons sentuhan. Jangan mengembalikan tampilan super, karena tidak tergantung pada tampilan ini apakah tampilan supernya harus menerima sentuhan atau tidak!Solusi ini adalah:
pointInside:withEvent:
untuk mengembalikan area tertentu yang dapat disentuh).Saya menggunakan ini cukup sering sehingga saya telah mengabstraksikannya menjadi subclass untuk menyimpan subclass view yang tidak berguna untuk satu timpaan. Sebagai bonus, tambahkan properti agar dapat dikonfigurasi:
Lalu jadilah liar dan gunakan tampilan ini di mana pun Anda mungkin menggunakan dataran
UIView
. Konfigurasi itu adalah yang sederhana seperti pengaturanonlyRespondToTouchesInSubviews
untukYES
.sumber
Ada beberapa cara untuk mengatasinya. Favorit saya adalah mengganti hitTest: withEvent: dalam tampilan yang merupakan tampilan super umum (mungkin secara tidak langsung) ke tampilan yang bertentangan (terdengar seperti Anda menyebutnya A dan B). Misalnya, sesuatu seperti ini (di sini A dan B adalah pointer UIView, di mana B adalah yang "tersembunyi", yang biasanya diabaikan):
Anda juga dapat memodifikasi
pointInside:withEvent:
metode seperti yang disarankan oleh gyim. Hal ini memungkinkan Anda mencapai hasil yang pada dasarnya sama dengan secara efektif "membuat lubang" di A, setidaknya untuk sentuhan.Pendekatan lain adalah penerusan acara, yang berarti menimpa
touchesBegan:withEvent:
dan metode serupa (sepertitouchesMoved:withEvent:
dll) untuk mengirim beberapa sentuhan ke objek yang berbeda dari tempat mereka pertama kali pergi. Misalnya, di A, Anda bisa menulis sesuatu seperti ini:Namun, ini tidak selalu berfungsi seperti yang Anda harapkan! Hal utama adalah bahwa kontrol bawaan seperti UIButton akan selalu mengabaikan sentuhan yang diteruskan. Karena itu, pendekatan pertama lebih dapat diandalkan.
Ada posting blog bagus yang menjelaskan semua ini secara lebih rinci, bersama dengan proyek xcode kecil yang berfungsi untuk mendemonstrasikan ide, tersedia di sini:
http://bynomial.com/blog/?p=74
sumber
Anda harus mengatur
upperView.userInteractionEnabled = NO;
, jika tidak, tampilan atas akan menghalangi sentuhan.Versi Interface Builder ini adalah kotak centang di bagian bawah panel View Attributes yang disebut "User Interaction Enabled". Hapus centangnya dan Anda sebaiknya pergi.
sumber
Implementasi kustom pointInside: withEvent: memang tampak seperti cara yang harus dilakukan, tetapi berurusan dengan koordinat hard-code tampak aneh bagi saya. Jadi saya akhirnya memeriksa apakah CGPoint berada di dalam tombol CGRect menggunakan fungsi CGRectContainsPoint ():
sumber
Akhir-akhir ini saya menulis kelas yang akan membantu saya dengan hal itu. Menggunakannya sebagai kelas khusus untuk
UIButton
atauUIView
akan meneruskan peristiwa sentuh yang dijalankan pada piksel transparan.Solusi ini agak lebih baik daripada jawaban yang diterima karena Anda masih dapat mengklik a
UIButton
yang berada di bawah semi transparanUIView
sementara bagian yang tidak transparanUIView
masih akan merespons peristiwa sentuh.Seperti yang Anda lihat di GIF, tombol Giraffe adalah persegi panjang sederhana tetapi peristiwa sentuh di area transparan diteruskan ke kuning di
UIButton
bawahnya.Tautan ke kelas
sumber
Saya kira saya agak terlambat ke pesta ini, tetapi saya akan menambahkan solusi yang mungkin ini:
Jika Anda menggunakan kode ini untuk mengganti fungsi hitTest standar UIView khusus, ini HANYA akan mengabaikan tampilan itu sendiri. Setiap sub-tampilan dari tampilan tersebut akan mengembalikan kliknya secara normal, dan setiap klik yang akan masuk ke tampilan itu sendiri diteruskan ke superview-nya.
-Abu
sumber
[self superview]
. dokumentasi pada metode ini menyatakan "Mengembalikan turunan terjauh penerima dalam hierarki tampilan (termasuk dirinya sendiri) yang berisi titik tertentu" dan "Mengembalikan nihil jika titik benar-benar berada di luar hierarki tampilan penerima". Saya pikir Anda harus kembalinil
. ketika Anda mengembalikan nihil, kontrol akan meneruskan ke superview untuk memeriksa apakah ada hit atau tidak. jadi pada dasarnya ini akan melakukan hal yang sama, kecuali mengembalikan superview dapat merusak sesuatu di masa mendatang.Hanya membaca Jawaban yang Diterima dan meletakkan ini di sini untuk referensi saya. Jawaban yang Diterima bekerja dengan sempurna. Anda dapat memperluasnya seperti ini untuk memungkinkan subview tampilan Anda menerima sentuhan, ATAU meneruskannya ke tampilan di belakang kami:
Catatan: Anda bahkan tidak perlu melakukan rekursi pada subview tree, karena setiap
pointInside:withEvent:
metode akan menanganinya untuk Anda.sumber
Menonaktifkan properti userInteraction mungkin bisa membantu. Misalnya:
(Catatan: Dalam kode di atas, 'self' mengacu pada tampilan)
Dengan cara ini, Anda hanya dapat menampilkan di topView, tetapi tidak akan mendapatkan input pengguna. Semua sentuhan pengguna akan melalui tampilan ini dan tampilan bawah akan merespons mereka. Saya akan menggunakan topView ini untuk menampilkan gambar transparan, atau menganimasikannya.
sumber
Pendekatan ini cukup bersih dan memungkinkan subview transparan tidak bereaksi terhadap sentuhan juga. Cukup buat subkelas
UIView
dan tambahkan metode berikut ke implementasinya:sumber
Solusi saya di sini:
Semoga ini membantu
sumber
Ada sesuatu yang dapat Anda lakukan untuk menghentikan sentuhan di kedua tampilan.
Pandangan atas:
Tapi itulah idenya.
sumber
Ini adalah versi Swift:
sumber
Cepat 3
sumber
Saya belum pernah membuat antarmuka pengguna lengkap menggunakan UI toolkit, jadi saya tidak punya banyak pengalaman dengannya. Inilah yang menurut saya harus berhasil.
Setiap UIView, dan ini UIWindow, memiliki properti
subviews
, yang merupakan NSArray yang berisi semua subview.Subview pertama yang Anda tambahkan ke tampilan akan menerima indeks 0, dan indeks berikutnya 1 dan seterusnya. Anda juga bisa mengganti
addSubview:
denganinsertSubview: atIndex:
atauinsertSubview:aboveSubview:
dan metode semacam itu yang dapat menentukan posisi subview Anda dalam hierarki.Jadi periksa kode Anda untuk melihat tampilan mana yang Anda tambahkan pertama kali ke UIWindow Anda. Itu akan menjadi 0, yang lainnya akan menjadi 1.
Sekarang, dari salah satu subview Anda, untuk mencapai subview lainnya Anda akan melakukan hal berikut:
Beri tahu saya jika itu berhasil untuk kasus Anda!
(di bawah penanda ini adalah jawaban saya sebelumnya):
Jika tampilan perlu berkomunikasi satu sama lain, tampilan harus melakukannya melalui pengontrol (yaitu, menggunakan model MVC yang populer ).
Saat Anda membuat tampilan baru, Anda dapat memastikannya mendaftar sendiri dengan pengontrol.
Jadi tekniknya adalah memastikan pandangan Anda terdaftar dengan pengontrol (yang dapat menyimpannya dengan nama atau apa pun yang Anda inginkan dalam Kamus atau Array). Anda dapat meminta pengontrol mengirim pesan untuk Anda, atau Anda bisa mendapatkan referensi ke tampilan dan berkomunikasi dengannya secara langsung.
Jika view Anda tidak memiliki link ke controller (yang mungkin terjadi) maka Anda dapat menggunakan metode singletons dan / atau class untuk mendapatkan referensi ke controller Anda.
sumber
Menurut saya, cara yang benar adalah menggunakan rantai tampilan yang dibangun ke dalam hierarki tampilan. Untuk subview Anda yang didorong ke tampilan utama, jangan gunakan UIView generik, tetapi gunakan subclass UIView (atau salah satu variannya seperti UIImageView) untuk membuat MYView: UIView (atau supertipe apa pun yang Anda inginkan, seperti UIImageView). Dalam implementasi untuk YourView, terapkan metode touchesBegan. Metode ini kemudian akan dipanggil saat tampilan tersebut disentuh. Yang perlu Anda miliki dalam implementasi itu adalah metode instance:
this touchesBegan adalah api responder, jadi Anda tidak perlu mendeklarasikannya di antarmuka publik atau pribadi Anda; itu salah satu api ajaib yang harus Anda ketahui. Self.superview ini pada akhirnya akan memunculkan permintaan ke viewController. Di viewController, lalu, terapkan touchesBegan ini untuk menangani sentuhan.
Perhatikan bahwa lokasi sentuhan (CGPoint) secara otomatis disesuaikan relatif terhadap tampilan yang melingkupinya untuk Anda karena itu dipantulkan ke rantai hierarki tampilan.
sumber
Hanya ingin memposting ini, karena saya memiliki masalah yang agak mirip, menghabiskan banyak waktu untuk mencoba menerapkan jawaban di sini tanpa hasil. Apa yang akhirnya saya lakukan:
dan menerapkan
UIGestureRecognizerDelegate
:Tampak bawah adalah pengontrol navigasi dengan jumlah segue dan saya memiliki semacam pintu di atasnya yang bisa ditutup dengan gerakan pan. Semuanya tertanam di VC lain. Bekerja seperti pesona. Semoga ini membantu.
sumber
Implementasi Swift 4 untuk solusi berbasis HitTest
sumber
Berasal dari jawaban Stuart yang sangat baik, dan sebagian besar sangat mudah, dan implementasi Segev yang berguna, berikut adalah paket Swift 4 yang dapat Anda masukkan ke dalam proyek apa pun:
Dan kemudian dengan hitTest:
sumber