Pertanyaan interaksi di luar batas uiview


Apakah mungkin untuk UIButton (atau kontrol lain dalam hal ini) untuk menerima peristiwa sentuhan ketika bingkai UIButton terletak di luar bingkai orang tua itu? Karena ketika saya mencoba ini, UIButton saya tampaknya tidak dapat menerima kejadian apa pun. Bagaimana saya mengatasi hal ini?


75
2018-03-25 13:21


asal


Jawaban:


Iya nih. Anda dapat mengganti hitTest:withEvent: metode untuk mengembalikan tampilan untuk kumpulan poin yang lebih besar dari tampilan tersebut. Lihat Referensi Kelas UIView.

Edit: Contoh:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    CGFloat radius = 100.0;
    CGRect frame = CGRectMake(-radius, -radius,
                              self.frame.size.width + radius,
                              self.frame.size.height + radius);

    if (CGRectContainsPoint(frame, point)) {
        return self;
    }
    return nil;
}

Edit 2: (Setelah klarifikasi :) Untuk memastikan bahwa tombol diperlakukan sebagai dalam batasan orang tua, Anda perlu mengesampingkan pointInside:withEvent: di induk untuk memasukkan bingkai tombol.

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    if (CGRectContainsPoint(self.view.bounds, point) ||
        CGRectContainsPoint(button.view.frame, point))
    {
        return YES;
    }
    return NO;
}

Catatan kode hanya di sana untuk menimpa pointInside tidak sepenuhnya benar. Saat Summon menjelaskan di bawah ini, lakukan ini:

-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
    {
    if ( CGRectContainsPoint(self.oversizeButton.frame, point) )
        return YES;

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

Perhatikan bahwa Anda kemungkinan besar akan melakukannya self.oversizeButton sebagai IBOutlet di subclass UIView ini; maka Anda cukup menyeret "tombol kebesaran" yang dimaksud, ke, tampilan khusus yang dimaksud. (Atau, jika karena alasan tertentu Anda melakukan ini banyak dalam sebuah proyek, Anda akan memiliki subclass UIButton khusus, dan Anda dapat melihat daftar subview Anda untuk kelas-kelas tersebut.) Semoga itu membantu.


83
2018-03-25 13:36



@jnic, saya bekerja di iOS SDK 5.0 dan agar kode Anda berfungsi dengan baik, saya harus melakukan ini:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
if (CGRectContainsPoint(button.frame, point)) {
    return YES;
}
return [super pointInside:point withEvent:event]; }

Tampilan kontainer dalam kasus saya adalah UIButton dan semua elemen anak juga UIButtons yang dapat bergerak di luar batas UIButton induk.

Terbaik


23
2018-02-02 14:22



Di tampilan orang tua Anda dapat mengganti metode uji hit:

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

    if (CGRectContainsPoint(_myButton.bounds, translatedPoint)) {
        return [_myButton hitTest:translatedPoint withEvent:event];
    }
    return [super hitTest:point withEvent:event];

}

Dalam hal ini, jika titik itu berada dalam batas-batas tombol Anda, Anda meneruskan panggilan ke sana; jika tidak, kembali ke implementasi awal.


16
2018-05-25 04:17



Cepat:

Di mana targetView adalah tampilan yang Anda inginkan untuk menerima peristiwa (yang mungkin seluruhnya atau sebagian terletak di luar bingkai pandangan induknya).

override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
        let pointForTargetView: CGPoint = targetView.convertPoint(point, fromView: self)
        if CGRectContainsPoint(targetView.bounds, pointForTargetView) {
            return closeButton
        }
        return super.hitTest(point, withEvent: event)
}

7
2018-04-25 19:26



Dalam kasus saya, saya punya UICollectionViewCell subkelas yang berisi UIButton. Saya dinonaktifkan clipsToBounds pada sel dan tombol itu terlihat di luar batas sel. Namun, tombol itu tidak menerima acara sentuhan. Saya dapat mendeteksi peristiwa sentuhan pada tombol dengan menggunakan jawaban Jack: https://stackoverflow.com/a/30431157/3344977

Ini adalah versi Swift:

override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {

    let translatedPoint = button.convertPoint(point, fromView: self)

    if (CGRectContainsPoint(button.bounds, translatedPoint)) {
        print("Your button was pressed")
        return button.hitTest(translatedPoint, withEvent: event)
    }
    return super.hitTest(point, withEvent: event)
}

5
2017-11-30 23:29



Mengapa ini terjadi?

Ini karena ketika subview Anda berada di luar batas superview Anda, sentuh peristiwa yang benar-benar terjadi pada subview tersebut tidak akan dikirimkan ke subview itu. Namun, itu AKAN dikirim ke superview-nya.

Terlepas dari apakah tidak ada sub-tab yang terpotong secara visual, acara sentuhan selalu menghormati batas persegi panjang dari tampilan superview target. Dengan kata lain, peristiwa sentuhan yang terjadi di bagian tampilan yang terletak di luar persegi panjang bita superview-nya tidak dikirim ke tampilan itu. Link

apa yang kamu butuhkan?

Ketika superview Anda menerima acara sentuh yang disebutkan di atas, Anda harus memberi tahu UIKit secara eksplisit bahwa subview saya harus menjadi orang yang menerima acara sentuh ini.

Bagaimana dengan kode?

Di superview Anda, implementasikan func hitTest(_ point: CGPoint, with event: UIEvent?)

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
        if isHidden || alpha == 0 || clipsToBounds { return nil }
        // convert the point into subview's coordinate system
        let subviewPoint = self.convert(point, to: subview)
        // if the converted point lies in subview's bound, tell UIKit that subview should be the one that receives this event
        if ! subview.isHidden && subview.bounds.contains(subviewPoint) { return subview }
        return nil
    }

2
2018-01-10 22:46



Bagi saya (untuk orang lain), jawabannya adalah tidak untuk mengganti hitTest metode, melainkan pointInside metode. Saya harus melakukan ini hanya di dua tempat.

The Superview Ini adalah pandangan yang jika itu terjadi clipsToBounds set ke benar, itu akan membuat seluruh masalah ini hilang. Jadi, inilah kesederhanaan saya UIView di Swift 3:

class PromiscuousView : UIView {
    override func point(inside point: CGPoint,
               with event: UIEvent?) -> Bool {
        return true
    }
} 

Subbagian Jarak tempuh Anda mungkin bervariasi, tetapi dalam kasus saya, saya juga harus menimpa pointInside metode untuk subview yang telah memutuskan sentuhan itu di luar batas. Milik saya di Objective-C, jadi:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    WEPopoverController *controller = (id) self.delegate;
    if (self.takeHitsOutside) {
        return YES;
    } else {
        return [super pointInside:point withEvent:event];
    }
}

Jawaban ini (dan beberapa orang lain dengan pertanyaan yang sama) dapat membantu menjernihkan pemahaman Anda.


0
2018-01-09 15:13