Mengizinkan interaksi dengan UIView di bawah UIView lain

115

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?

delany
sumber
2
Semuanya dijelaskan di sini: developer.apple.com/iphone/library/documentation/iPhone/… Tapi pada dasarnya, timpa hitTest: withEvent :, mereka bahkan menyediakan sampel kode.
nash
Saya telah menulis kelas kecil hanya untuk itu. (Menambahkan contoh dalam jawaban). Solusinya di sana agak lebih baik daripada jawaban yang diterima karena Anda masih dapat mengklik a UIButtonyang berada di bawah semi transparan UIViewsedangkan bagian non transparan UIViewmasih akan merespons peristiwa sentuh.
Segev

Jawaban:

97

Anda harus membuat subclass UIView untuk tampilan teratas Anda dan mengganti metode berikut:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    // UIView will be "transparent" for touch events if we return NO
    return (point.y < MIDDLE_Y1 || point.y > MIDDLE_Y2);
}

Anda juga dapat melihat metode hitTest: event:.

gyim
sumber
19
Apa yang direpresentasikan middle_y1 / y2 di sini?
Jason Renaldo
Tidak yakin apa yang dilakukan returnpernyataan itu, tetapi return CGRectContainsPoint(eachSubview.frame, point)berhasil untuk saya. Jawaban yang sangat membantu sebaliknya
n00neimp0rtant
Bisnis MIDDLE_Y1 / Y2 hanyalah sebuah contoh. Fungsi ini akan "transparan" untuk acara sentuh di MIDDLE_Y1<=y<=MIDDLE_Y2area tersebut.
gyim
41

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 .

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    UIView *hitView = [super hitTest:point withEvent:event];
    if (hitView == self) return nil;
    return hitView;
}

[super hitTest:point withEvent:event]akan mengembalikan tampilan terdalam dalam hierarki tampilan yang disentuh. Jika hitView == self(yaitu, jika tidak ada subview di bawah titik sentuh), kembali nil, 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:

  • nyaman , karena tidak memerlukan referensi ke tampilan / subview / objek lain;
  • umum , karena ini berlaku untuk tampilan apa pun yang bertindak murni sebagai wadah untuk sub-tampilan yang dapat disentuh, dan konfigurasi sub-tampilan tidak memengaruhi cara kerjanya (seperti yang terjadi jika Anda mengganti pointInside:withEvent:untuk mengembalikan area tertentu yang dapat disentuh).
  • sangat mudah , tidak banyak kode ... dan konsepnya tidak sulit untuk dipahami.

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:

@interface ISView : UIView
@property(nonatomic, assign) BOOL onlyRespondToTouchesInSubviews;
@end

@implementation ISView
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    UIView *hitView = [super hitTest:point withEvent:event];
    if (hitView == self && onlyRespondToTouchesInSubviews) return nil;
    return hitView;
}
@end

Lalu jadilah liar dan gunakan tampilan ini di mana pun Anda mungkin menggunakan dataran UIView. Konfigurasi itu adalah yang sederhana seperti pengaturan onlyRespondToTouchesInSubviewsuntuk YES.

Stuart
sumber
2
Satu-satunya jawaban yang benar. untuk memperjelas, jika Anda ingin mengabaikan sentuhan pada tampilan, tetapi tidak pada tombol (katakanlah) yang terdapat dalam tampilan , lakukan seperti yang dijelaskan Stuart. (Saya biasanya menyebutnya "tampilan pemegang" karena tidak berbahaya dapat "menahan" beberapa tombol, tetapi, itu tidak mempengaruhi apa pun yang "di bawah" pemegang.)
Fattie
Beberapa solusi lain yang menggunakan titik mengalami masalah jika tampilan Anda dapat digulir, seperti UITableView atau UICollectionView dan Anda telah menggulir ke atas atau ke bawah. Namun solusi ini, berfungsi terlepas dari pengguliran.
pajevic
31

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

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    CGPoint pointInB = [B convertPoint:point fromView:self];

    if ([B pointInside:pointInB withEvent:event])
        return B;

    return [super hitTest:point withEvent:event];
}

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 (seperti touchesMoved: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:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    if ([self shouldForwardTouches:touches]) {
        [B touchesBegan:touches withEvent:event];
    }
    else {
        // Do whatever A does with touches.
    }
}

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

Tyler
sumber
Masalah dengan solusi ini - mengesampingkan hitTest pada tampilan super umum - adalah bahwa hal itu tidak memungkinkan tampilan di bawah berfungsi sepenuhnya dengan benar ketika tampilan di bawah adalah salah satu dari seluruh rangkaian tampilan yang dapat digulir (MapView dll). Titik utama Di dalam pada tampilan atas seperti yang disarankan oleh gyim di bawah ini berfungsi dalam semua kasus sejauh yang saya tahu.
delany
@ Delany, Itu tidak benar; Anda dapat memiliki tampilan yang dapat digulir di bawah tampilan lain dan membiarkan keduanya bekerja dengan menimpa hitTest. Berikut beberapa contoh kode: bynomial.com/blogfiles/Temp32.zip
Tyler
Hei. Tidak semua tampilan yang dapat digulir - hanya beberapa ... Saya mencoba kode pos Anda dari atas, mengubah UIScrollView menjadi (misalnya) MKMapView dan tidak berhasil. Keran berfungsi - pengguliran yang tampaknya menjadi masalah.
Delany
Oke, saya memeriksanya dan mengonfirmasi bahwa hitTest tidak berfungsi seperti yang Anda inginkan dengan MKMapView. Anda benar tentang itu, @delany; meskipun itu berfungsi dengan benar dengan UIScrollView. Saya bertanya-tanya mengapa MKMapView gagal?
Tyler
@Tyler Seperti yang Anda sebutkan, bahwa "Hal utama adalah bahwa kontrol bawaan seperti UIButton akan selalu mengabaikan sentuhan yang diteruskan", saya ingin tahu bagaimana Anda mengetahuinya dan apakah itu adalah dokumen resmi untuk menjelaskan perilaku ini. Saya menghadapi masalah bahwa ketika UIButton memiliki subview UIView biasa, itu tidak akan merespon untuk menyentuh kejadian di batas subview. Dan saya menemukan bahwa acara tersebut diteruskan ke UIButton dengan benar sebagai perilaku default UIView, tetapi saya tidak yakin itu adalah fitur yang ditentukan atau hanya bug. Tolong tunjukkan saya dokumentasi tentang ini? Terima kasih banyak dengan tulus.
Neal.Marlin
29

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.

Benjamin Cox
sumber
Maaf - seharusnya mengatakan. Saya masih ingin dapat berinteraksi dengan objek di UIView atas.
delany
Tetapi tampilan atas tidak dapat menerima sentuhan apa pun, termasuk tombol di Tampilan atas.
imcaptor
2
Solusi ini berhasil untuk saya. Saya tidak membutuhkan pandangan atas untuk bereaksi terhadap sentuhan sama sekali.
TJ
11

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 ():

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    return (CGRectContainsPoint(disclosureButton.frame, point));
}
samvermette
sumber
8

Akhir-akhir ini saya menulis kelas yang akan membantu saya dengan hal itu. Menggunakannya sebagai kelas khusus untuk UIButtonatau UIViewakan meneruskan peristiwa sentuh yang dijalankan pada piksel transparan.

Solusi ini agak lebih baik daripada jawaban yang diterima karena Anda masih dapat mengklik a UIButtonyang berada di bawah semi transparan UIViewsementara bagian yang tidak transparan UIViewmasih akan merespons peristiwa sentuh.

GIF

Seperti yang Anda lihat di GIF, tombol Giraffe adalah persegi panjang sederhana tetapi peristiwa sentuh di area transparan diteruskan ke kuning di UIButtonbawahnya.

Tautan ke kelas

Segev
sumber
2
Karena kode Anda tidak terlalu panjang, Anda harus menyertakan bagian yang relevan dalam jawaban Anda, jika proyek Anda dipindahkan atau dihapus di beberapa titik di masa mendatang.
Gavin
Terima kasih, solusi Anda berfungsi untuk kasus saya di mana saya memerlukan bagian tidak transparan dari UIView saya untuk menanggapi peristiwa sentuh, sementara bagian transparan tidak. Cemerlang!
Bruce
@Bruce Senang itu membantu Anda!
Segev
4

Saya kira saya agak terlambat ke pesta ini, tetapi saya akan menambahkan solusi yang mungkin ini:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    UIView *hitView = [super hitTest:point withEvent:event];
    if (hitView != self) return hitView;
    return [self superview];
}

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

Abu
sumber
1
ini adalah metode pilihan saya kecuali, saya rasa Anda tidak harus kembali [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 kembali nil. 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.
jasongregori
Tentu, itu mungkin bijaksana (perhatikan tanggal pada jawaban asli saya - melakukan lebih banyak pengkodean sejak itu)
Ash
4

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:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    // If one of our subviews wants it, return YES
    for (UIView *subview in self.subviews) {
        CGPoint pointInSubview = [subview convertPoint:point fromView:self];
        if ([subview pointInside:pointInSubview withEvent:event]) {
            return YES;
        }
    }
    // otherwise return NO, as if userInteractionEnabled were NO
    return NO;
}

Catatan: Anda bahkan tidak perlu melakukan rekursi pada subview tree, karena setiap pointInside:withEvent:metode akan menanganinya untuk Anda.

Dan Rosenstark
sumber
3

Menonaktifkan properti userInteraction mungkin bisa membantu. Misalnya:

UIView * topView = [[TOPView alloc] initWithFrame:[self bounds]];
[self addSubview:topView];
[topView setUserInteractionEnabled:NO];

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

Aditya
sumber
3

Pendekatan ini cukup bersih dan memungkinkan subview transparan tidak bereaksi terhadap sentuhan juga. Cukup buat subkelas UIViewdan tambahkan metode berikut ke implementasinya:

@implementation PassThroughUIView

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    for (UIView *v in self.subviews) {
        CGPoint localPoint = [v convertPoint:point fromView:self];
        if (v.alpha > 0.01 && ![v isHidden] && v.userInteractionEnabled && [v pointInside:localPoint withEvent:event])
            return YES;
    }
    return NO;
}

@end
prodos
sumber
2

Solusi saya di sini:

-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    CGPoint pointInView = [self.toolkitController.toolbar convertPoint:point fromView:self];

    if ([self.toolkitController.toolbar pointInside:pointInView withEvent:event]) {
       self.userInteractionEnabled = YES;
    } else {
       self.userInteractionEnabled = NO;
    }

    return [super hitTest:point withEvent:event];
}

Semoga ini membantu

Jerry
sumber
2

Ada sesuatu yang dapat Anda lakukan untuk menghentikan sentuhan di kedua tampilan.

Pandangan atas:

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
   // Do code in the top view
   [bottomView touchesBegan:touches withEvent:event]; // And pass them on to bottomView
   // You have to implement the code for touchesBegan, touchesEnded, touchesCancelled in top/bottom view.
}

Tapi itulah idenya.

Alexandre Cassagne
sumber
Ini tentu saja mungkin - tetapi banyak pekerjaan (Anda harus menggulung objek sensitif sentuhan Anda sendiri di lapisan bawah (misalnya tombol), saya kira?) Dan tampaknya aneh bahwa seseorang harus menggulung objek Anda sendiri dalam hal ini. cara untuk mendapatkan perilaku yang tampaknya intuitif.
delany
Saya tidak yakin mungkin kita harus mencobanya.
Alexandre Cassagne
2

Ini adalah versi Swift:

override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {
    return !CGRectContainsPoint(buttonView.frame, point)
}
Esqarrouth
sumber
2

Cepat 3

override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
    for subview in subviews {
        if subview.frame.contains(point) {
            return true
        }
    }
    return false
}
pyRabbit.dll
sumber
1

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:dengan insertSubview: 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:

UIView * theOtherView = [[[self superview] subviews] objectAtIndex: 0];
// or using the properties syntax
UIView * theOtherView = [self.superview.subviews objectAtIndex:0];

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.

nash
sumber
Terima kasih atas balasan Anda - tetapi saya tidak yakin saya mengerti. Kedua tampilan memiliki pengontrol - masalahnya adalah, dengan satu tampilan di atas yang lain, tampilan bawah tidak mengambil peristiwa (dan meneruskannya ke pengontrolnya), bahkan melalui tidak ada objek yang benar-benar 'memblokir' peristiwa tersebut di tampilan atas.
delany
Apakah Anda memiliki UIWindow di bagian atas UIViews kami? Jika Anda melakukannya, peristiwa tersebut harus disebarkan dan Anda tidak perlu melakukan "keajaiban" apa pun. Bacalah tentang [Window and Views] [1] di Apple Dev center (dan tentu saja, tambahkan komentar lain jika ini tidak membantu Anda!) [1]: developer.apple.com/iphone/library/documentation/ iPhone /…
nash
Ya, tentu saja - UIWindow di bagian atas hierarki.
delany
Saya telah memperbarui jawaban saya untuk menyertakan kode untuk melalui hierarki tampilan. Beri tahu saya jika Anda membutuhkan bantuan lainnya!
nash
Terima kasih atas bantuan Anda nash - tetapi saya cukup berpengalaman dalam membangun antarmuka ini dan antarmuka saya saat ini diatur dengan benar sejauh yang saya tahu. Masalahnya tampaknya menjadi perilaku default tampilan penuh saat ditempatkan di atas yang lain.
delany
1

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:

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event ;
{   // cannot handle this event. pass off to super
    [self.superview touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event]; }

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.

PapaSmurf
sumber
1

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:

 for(UIGestureRecognizer *recognizer in topView.gestureRecognizers)
 {
     recognizer.delegate=self;
     [bottomView addGestureRecognizer:recognizer];   
 }
 topView.abView.userInteractionEnabled=NO; 

dan menerapkan UIGestureRecognizerDelegate:

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

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.

stringCode
sumber
1

Implementasi Swift 4 untuk solusi berbasis HitTest

let hitView = super.hitTest(point, with: event)
if hitView == self { return nil }
return hitView
BiscottiGelato
sumber
0

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:

extension UIColor {
    static func colorOfPoint(point:CGPoint, in view: UIView) -> UIColor {

        var pixel: [CUnsignedChar] = [0, 0, 0, 0]

        let colorSpace = CGColorSpaceCreateDeviceRGB()
        let bitmapInfo = CGBitmapInfo(rawValue: CGImageAlphaInfo.premultipliedLast.rawValue)

        let context = CGContext(data: &pixel, width: 1, height: 1, bitsPerComponent: 8, bytesPerRow: 4, space: colorSpace, bitmapInfo: bitmapInfo.rawValue)

        context!.translateBy(x: -point.x, y: -point.y)

        view.layer.render(in: context!)

        let red: CGFloat   = CGFloat(pixel[0]) / 255.0
        let green: CGFloat = CGFloat(pixel[1]) / 255.0
        let blue: CGFloat  = CGFloat(pixel[2]) / 255.0
        let alpha: CGFloat = CGFloat(pixel[3]) / 255.0

        let color = UIColor(red:red, green: green, blue:blue, alpha:alpha)

        return color
    }
}

Dan kemudian dengan hitTest:

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    guard UIColor.colorOfPoint(point: point, in: self).cgColor.alpha > 0 else { return nil }
    return super.hitTest(point, with: event)
}
brandonscript
sumber