2013-08-05 9 views
11

2 tane görüşüme sahibim, ama 1 görüntüyü (neredeyse) daha büyük yapmak istiyorum. Eğer tapGesture'ı v1'e yerleştirirsem, hafifçe vurma hareketi büyük isabet alanıyla çalışır, ancak tapGesture'u v2'ye yerleştirirsem işe yaramıyor (aslında tapGesture'ı tanımaz, orijinal sınırlar içinde olmasa bile) TestView1 yönteminden geçtiğim ve çerçevede yer aldığım noktalara rağmen.hitTest: WithEvent ve Subviews

#import "ViewController.h" 

@interface TestView1 : UIView 
@end 

@implementation TestView1 

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

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

@end 

@interface TestView2 : UIView 
@end 

@implementation TestView2 

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

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

@interface ViewController() 
@end 

@implementation ViewController 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    TestView1 *v1 = [[TestView1 alloc] initWithFrame:CGRectMake(50.f, 50.f, 100.f, 100.f)]; 
    [self.view addSubview:v1]; 

    TestView2 *v2 = [[TestView2 alloc] initWithFrame:CGRectMake(0.f, 0.f, 100.f, 100.f)]; 
    v2.backgroundColor = UIColor.yellowColor; 
    [v1 addSubview:v2]; 

    UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(panGesture:)]; 
    [v2 addGestureRecognizer:gesture]; 
} 

- (void) panGesture:(UIPanGestureRecognizer *)recognizer 
{ 
    NSLog(@"tap"); 
} 
@end 

cevap

10

Görünüm hiyerarşisini geçmiyorsunuz. belgelerden; withEvent: mesaj her subview bir dokunuş olayı almalarının gerektiğini Subview belirlemek için

Bu yöntem pointInside göndererek görünüm hiyerarşisi gezinir. PointInside: withEvent: YES değerini döndürürse, alt görünümün hiyerarşisi aktarılır; aksi halde, görünüm hiyerarşisinin dalı göz ardı edilir.

Sadece pointInside:withEvent:'u uygulamanız yeterlidir. hitTest:withEvent:'u geçersiz kılmamalısınız çünkü standart uygulama, pointInside:withEvent: uygulamanızı çağırır ve hiyerarşiyi geçmenin tüm zor işlerini sizin için yapar.

böyle Uygulanışı:

@interface TestView1 : UIView 
@end 

@implementation TestView1 

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

    return (CGRectContainsPoint(frame, point)); 
} 

@end 

@interface TestView2 : UIView 
@end 

@implementation TestView2 

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

    return (CGRectContainsPoint(frame, point)); 
} 

@end 

Şimdi, size kalmış iki görüşü gerekip gerekmediği. V1'in dokunulabilir alanını genişletmeyi zaten başardınız ve yukarıdaki kod ile v1'in v1 alt görünümü olarak yapabilirsiniz. Ancak, TestView1 ve TestView2 uygulamaları, TestView1 ve TestView2 uygulamalarıyla aynıdır (orijinal postanızda bile), bu nedenle bunları neden ayrı tutmanız gerekir? Aynı sınıfa ait v1 ve v2 örneklerini, ör. aşağıdaki gibi TestView ve bunları örneğini:

TestView *v1 = [[TestView alloc] initWithFrame:CGRectMake(50.f, 50.f, 100.f, 100.f)]; 
[self.view addSubview:v1]; 
v1.clipsToBounds = YES; 

TestView *v2 = [[TestView alloc] initWithFrame:CGRectMake(0.f, 0.f, 100.f, 100.f)]; 
v2.backgroundColor = UIColor.yellowColor; 
[v1 addSubview:v2]; 
+0

Sam'in kodu, dokunmatik alanı aşağı ve sağa doğru genişletir. CGFloat dolgu = 50 hakkında ne dersiniz? CGRect frame = CGRectMake (tuş takımı, -padding, self.frame.size.width + padding, self.frame.size.height + dolgu); – Nuthatch

+0

@Nuthatch Peki, orijinal kod Andy tarafından da yapılacak. Ama iyi bir nokta – LoPoBo

2

Sorunuzdan anladığım kadarıyla, V1'in üstüne daha büyük V2 eklediniz. bu nedenle V2 sadece V1 sınırları içerisinde olacak şekilde turacaktır. Böylece, jestiniz V2'nin ekstra alanında tanınmadı.

+0

Sence tamir edilebilir mi? –

+0

Üzgünüm, lütfen ihtiyacınızı detaylandırır mısınız? – Vignesh

+0

Sadece tapestranın V2 üzerinde olmasını istiyorsanız, daha büyük bir musluk alanıyla –

2

Sen uygulamak gerekir yöntemi: sonra

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

    if (CGRectContainsPoint(frame, point)) { 
     return YES; 
    } 

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

Ve: dokümantasyon

itibaren

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

    if (CGRectContainsPoint(frame, point)) { 
     return self; 
    } 
    return [super hitTest:point withEvent:event; 
} 

Bu yöntem pointInside göndererek görünüm hiyerarşisi geçtiği: withEvent: her bir alt gösterime hangi alt görünümü bir dokunma olayı almalıdır. PointInside: withEvent: , YES değerini döndürür, ardından alt görünümün hiyerarşisi aktarılır; aksi halde, görünüm hiyerarşisinin şubesi göz ardı edilir. Bu yöntemini kendinize nadiren aramanız gerekir, ancak alt görünümlerinden dokunma olaylarını gizlemek için bunu geçersiz kılabilirsiniz.

Bu yöntem, gizlenmiş, kullanıcı etkileşimlerini devre dışı bırakmış veya 0.01'den düşük bir alfa düzeyine sahip olan görüntüleme nesnelerini göz ardı eder. Bu yöntem , bir isabet belirlenirken görünümün içeriğini dikkate almaz. Bu nedenle, belirtilen nokta, söz konusu içeriğin sayısının saydam bölümünde yer alsa bile bir görünüm döndürülebilir.

5

V2'niz herhangi bir dokunma olayı almayacaktır. çünkü v1'in etrafındaki alanı tıklattığınızda, - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event içinde self döndürür, bu, tüm dokunma olaylarının hedefi olan "v1", hit-test görünümü olduğunu bildirmiş olduğunuz anlamına gelir.
senin V1 en dokunulabilir ares genişletmek için sağ yolu TestView1 ve TestView2 yılında - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event uygulamaktır:

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

    if (CGRectContainsPoint(frame, point)) { 
     return YES; 
    } 
    return [super pointInside:point withEvent:event]; 
} 

Yukarıdaki kod size v1 çevresini tıkladığınızda, bu Evet, öyle" beyan anlamına gelir bana dokundu ve kiminle başa çıkabileceğimi kontrol edeceğim. Belki de benim, belki de benim alt görüşümden biri ”. Böylece vuruş testi devam ediyor ve v1 alt görünümü v2'nin en üstteki görünümüdür, böylece v2 tıklama etkinliğinizin hedefidir.

v1'in v2'nin nasıl olduğunu bilmesini isteyebilirsiniz.

@implementation UIView 
//... 
//... 

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event 
{ 
    return CGRectContainsPoint(self.bounds, point); // Honestly tell others if the point is inside the bounds. That's the normal case. 
} 

// This method returns a hit-test view who or whose gesture recognizer is responsible for handling the events 
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event 
{ 
    for(UIView *aSubview in self.subviews) 
    { 
     // Ask each subview if the point falls in its area. 
     if ([aSubview pointInside:[self convertPoint:point toView:aSubview] point withEvent:event]) 
     { 
      return [aSubview hitTest:[self convertPoint:point toView:aSubview] withEvent:event]; 
     } 
    } 

    // If no one can handle the event. 
    return self; 
} 

//... 
//... 
@end 

Bu kod

basitlik için dikkate userInteractionEnable, alpha ve diğer şeyler almamış: Burada hile ortaya çıkarmak için sahte kodudur.
TestView1'nüzün - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event numaranızda [super pointInside:point withEvent:event];'u aradığınızda, noktanın v2 alanına düşüp düşmediğini sorun.Eğer v2'nin cevabı evet ise ve herhangi bir alt görüşüne sahip olmadığı için, v2 kendisini - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event içinde geri gönderecektir.

Bu tüm hikaye.

+0

"Hiç kimse olayı başaramaz" ise, noktanın 'kendi' içinde olup olmadığını da kontrol etmelisiniz. Aksi halde, tüm görünüm hiyerarşisinde yanlışlıkla dokunmayı engelleyebilirsiniz. –

2

sen bunu yapıyor yolu doğru yapılması mümkün olmakla zordur.

Tavsiye ettiğim şey, genel süper görünümlerine UITapGestureRecognizer eklemek ve daha sonra bağlantı konumuna bağlı olarak alıcının hangi görüntünün olduğuna karar vermektir; görünümler ortak Superview yoksa

- (void)onTap:(UITapGestureRecognizer*)tapRecognizer { 
    CGPoint touchPosition = [tapRecognizer locationInView:self]; 

    CGRect view1Frame = self.view1.frame; 
    view1Frame.width += 100; 
    view1Frame.height += 100; 

    if (CGRectContainsPoint(view1Frame, touchPosition)) { 
     [self.view1 handleTap]; 
     return; 
    } 

    ... 
} 

, sadece daha büyük bir şeffaf görünümde bunların her gömmek ve bu büyük görünümüne tanıyıcı ekleyin.

İlgili konular