2008-12-30 50 views
4

我在圖層背景視圖上有一個子圖層。子圖層的內容設置爲圖像參考,並且是25x25矩形。
當touchesBegan和touchesMoved方法被調用時,我對super層執行命中測試。實際上,擊中測試方法確實會在觸摸時返回子圖層,但只有在圖像的下半部分被觸摸時纔會返回。如果圖像的上半部分被觸摸,它將返回超級圖層。圖層觸擊測試僅在觸摸圖層下半部分時返回圖層

我知道iPhone OS補償了用戶觸摸的趨勢低於預期。即使我將子圖調整爲更大尺寸(50x50),它也表現出相同的行爲。

有什麼想法?

回答

0

感謝凱文...

我結束了剛剛重做我的代碼與UIViews。試圖弄清爲什麼UIView不知道什麼層被觸摸,這太麻煩了。我的理念背後的全部理由是,我將在屏幕上同時擁有100多個項目,並且認爲Layers在處理器上比UIViews更容易。我現在已經啓動並運行了應用程序,100個視圖並未給出任何打嗝。

我對別人只是命中測試UIViews可能的情況下堅持下去的建議,它使代碼更簡單

1

看來,該層不僅僅是接收底部像素的觸摸。相反,屏幕圖層上的「實際」和圖層內容似乎是由不同的CGRects定義的。圖像顯示在預期的座標上,而對觸摸作出響應的圖層位於圖像下方。通過下面,我的意思是圖像的起源在(200,200),並且響應觸摸的層的原點在(200,220)。

下面我發佈一些測試代碼,我用來重新創建問題。首先我的視圖子類,然後我的視圖控制器。任何推理這個問題的原因是不勝感激。

我的視圖子類:

#import "myView.h" 
#import <QuartzCore/QuartzCore.h> 


@implementation myView 


- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { 

    CGPoint currentLocation = [[touches anyObject] locationInView:self]; 

    CALayer *currentLayer = [self.layer hitTest:currentLocation]; 

    CGPoint center = [currentLayer position]; 

    NSLog([currentLayer valueForKey:@"isRootLayer"]); 

    if(![currentLayer valueForKey:@"isRootLayer"]) { 

     if (center.x != 200) { 

      [currentLayer setPosition:CGPointMake(200.0f, 200.0f)];  

     } else { 
      [currentLayer setPosition:CGPointMake(100.0f, 100.0f)];  

     } 
    } 
} 


- (id)initWithFrame:(CGRect)frame { 
    if (self = [super initWithFrame:frame]) { 
     // Initialization code 
    } 
    return self; 
} 


- (void)drawRect:(CGRect)rect { 
    // Drawing code 
} 


- (void)dealloc { 
    [super dealloc]; 
} 


@end 

我的視圖控制器:

#import "layerTestViewController.h" 
#import <QuartzCore/QuartzCore.h> 


#define ELEMENT_PERIOD_SIZE 50 
#define ELEMENT_GROUP_SIZE 50 

@implementation layerTestViewController 





// Implement viewDidLoad to do additional setup after loading the view, typically from a nib. 
- (void)viewDidLoad { 
    [super viewDidLoad]; 

    CALayer *myLayer = [CALayer layer]; 
    CGRect layerFrame =CGRectMake(0.0f, 0.0f, ELEMENT_GROUP_SIZE, ELEMENT_PERIOD_SIZE); 
    myLayer.frame = layerFrame; 

    [myLayer setName:[NSString stringWithString:@"test"]]; 
    [myLayer setValue:[NSString stringWithString:@"testkey"] forKey:@"key"]; 

    UIGraphicsBeginImageContext(layerFrame.size); 
    [[UIColor blueColor] set]; 
    UIRectFill(layerFrame); 
    UIImage *theImage = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 

    myLayer.contents = (id)[theImage CGImage]; 
    myLayer.position = CGPointMake(100.0f, 100.0f); 

    [self.view.layer addSublayer:myLayer]; 

    [self.view.layer setValue:[NSString stringWithString:@"YES"] forKey:@"isRootLayer"]; 
    NSLog([self.view.layer valueForKey:@"isRootLayer"]); 

} 




- (void)didReceiveMemoryWarning { 
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview 
    // Release anything that's not essential, such as cached data 
} 


- (void)dealloc { 
    [super dealloc]; 
} 

@end 
0

如果觸摸正在對下部只承認,一種可能性是另一個子視圖被覆蓋的這個上半子視圖。你有多個子視圖還是隻有一個圖像?如果您有多個子視圖,並且其中任何一個都具有clearColor的背景顏色,請嘗試爲其提供穩定的背景顏色以供測試。這種方式你會知道你的子視圖是否被另一個子視圖覆蓋。

希望有所幫助。

0

我簡化了我的代碼以找到問題。我在屏幕上只有一個子圖層,沒有子視圖。上面列出的代碼就是我在模擬器中運行的代碼。由於屏幕上只有2個圖層,主視圖的背層和添加的子圖層都不會影響命中測試。

如果不清楚,當觸摸子圖層的頂部時,點擊測試會返回背層圖層。另外,如果我在底層下面的某點觸摸底層,則底層會通過命中測試返回。

這很難解釋,但如果你運行代碼,它變得清晰。

感謝

-1

當我嘗試你的代碼,我得到幾乎正確的行爲,除了觸摸往往沒有在底層上的最邊緣的認可。至於發生了什麼,我有點困惑。你可能想嘗試做一些事情,比如當你註冊觸摸時,在發生觸摸的地方(比如5x5的某種顏色的方塊)拋出一個新的小圖層,然後在3秒後再次移除它。通過這種方式,您可以跟蹤CA認爲觸摸發生的位置與光標的實際位置。

順便說一句,你不需要爲你的藍色內容創建一個CGImage,你可以將圖層的backgroundColor設置爲[UIColor blueColor].CGColor

11

的則hitTest文檔說:

/* Returns the farthest descendant of the layer containing point 'p'. 
* Siblings are searched in top-to-bottom order. 'p' is in the 
* coordinate system of the receiver's superlayer. */ 

所以,你需要做的(這樣的事情):

CGPoint thePoint = [touch locationInView:self]; 
thePoint = [self.layer convertPoint:thePoint toLayer:self.layer.superlayer]; 
CALayer *theLayer = [self.layer hitTest:thePoint]; 

(從其他崗位重複的答案完整起見)

+0

謝謝!我遇到了同樣的問題,這讓我瘋狂。我仍然有點困惑,爲什麼它是必要的,但它似乎工作。 – 2009-03-20 22:51:45

1

接受的答案並不能解決問題,但schwa的答案確實如此。

我有一個窗口,一個視圖控制器和視圖。該視圖會在其圖層上接觸並調用hitTest:。我遇到了同樣的問題,並發現視圖中的點是正確的,但在hitTest:中,該點的y座標是20px off,恰好是狀態欄的高度。

通過將點映射到schwa建議的超層座標系,此問題得到修復。 「神祕」超級玩家是superview的根層。在我的情況下,它是窗口層(frame(0,0,320,480))。