2013-03-30 129 views
0

研究「如何檢測移動的UIImageView上的觸摸事件?」我遇到了幾個答案,我試圖將它們實現到我的應用程序。我遇到的任何東西似乎都可以工作。我會解釋我想要做什麼然後發佈我的代碼。任何想法,建議,意見或答案表示讚賞!如何檢測移動的UIImageView上的觸摸事件?

我的應用程序有幾張卡從左到右浮在屏幕上。這些卡片是各種各樣的顏色,遊戲的目的是將卡片拖放到它們相似顏色的相應容器中。如果用戶沒有足夠快地觸摸並拖動卡片,則卡片將簡單地漂離屏幕並且點將丟失。包含在正確容器中的牌越多,得分越高。

我已經使用核心動畫編寫了代碼,讓我的卡片從左到右浮動。這工作。然而,當試圖觸摸一張卡並將其拖向它的容器時,它不能正確地檢測到我正在觸摸該卡的UIImageView。

爲了測試我是否正確實現了移動卡的代碼,我還編寫了一些代碼,允許移動一張不移動的卡。在這種情況下,我的觸摸被檢測到,並相應地執行。

爲什麼我只能與固定卡互動?經過相當多的研究,似乎代碼:

options:UIViewAnimationOptionAllowUserInteraction 

是讓我的移動UIImage被檢測到的關鍵成分。但我試過這似乎沒有任何影響。

我另一個我可能會做錯的關鍵是沒有正確使用正確的表示層。我已經添加如下代碼到我的項目,我也只適用於非移動的物體:

UITouch *t = [touches anyObject]; 
UIView *myTouchedView = [t view]; 
CGPoint thePoint = [t locationInView:self.view]; 
if([_card.layer.presentationLayer hitTest:thePoint]) 
{ 
    NSLog(@"You touched a Card!"); 
} 
else{ 
    NSLog(@"backgound touched"); 
} 

嘗試這類事情,我被卡住了。這裏是我的代碼,多一點完全明白這一點:

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

@interface RBViewController() 
@property (nonatomic, strong) UIImageView *card; 

@end 

@implementation RBViewController 

- (void)viewDidLoad 
{ 
srand(time (NULL)); // will be used for random colors, drift speeds, and locations of cards 
[super viewDidLoad]; 

[self setOutFirstCardSet]; // this sends out 4 floating cards across the screen 

// the following creates a non-moving image that I can move. 
_card = [[UIImageView alloc] initWithFrame:CGRectMake(400,400,100,100)]; 
_card.image = [UIImage imageNamed:@"goodguyPINK.png"]; 
_card.userInteractionEnabled = YES; 
[self.view addSubview:_card]; 

} 

以下方法從一個隨機位置發出卡在屏幕的左側,使用核心動畫漂在屏幕上的卡。注意卡片的顏色,漂移的速度也會隨機生成。

-(void) setOutFirstCardSet 
{ 

for(int i=1; i < 5; i++) // sends out 4 shapes 
{ 
    CGRect cardFramei; 
    int startingLocation = rand() % 325; 

    CGRect cardOrigini = CGRectMake(-100,startingLocation + 37, 92, 87); 

    cardFramei.size = CGSizeMake(92, 87); 
    CGPoint origini; 

    origini.y = startingLocation + 37; 
    origini.x = 1200; 
    cardFramei.origin = origini; 

    _card.userInteractionEnabled = YES; 
    _card = [[UIImageView alloc] initWithFrame:cardOrigini]; 

    int randomColor = rand() % 7; 
    if(randomColor == 0) 
    { 
     _card.image = [UIImage imageNamed:@"goodguy.png"]; 
    } 
    else if (randomColor == 1) 
    { 
     _card.image = [UIImage imageNamed:@"goodguyPINK.png"]; 
    } 
    else if (randomColor == 2) 
    { 
     _card.image = [UIImage imageNamed:@"goodGuyPURPLE.png"]; 
    } 
    else if (randomColor == 3) 
    { 
     _card.image = [UIImage imageNamed:@"goodGuyORANGE.png"]; 
    } 
    else if (randomColor == 4) 
    { 
     _card.image = [UIImage imageNamed:@"goodGuyLightPINK.png"]; 
    } 
    else if (randomColor == 5) 
    { 
     _card.image = [UIImage imageNamed:@"goodGuyBLUE.png"]; 
    } 
    else if (randomColor == 6) 
    { 
     _card.image = [UIImage imageNamed:@"goodGuyGREEN.png"]; 
    } 

    _card.userInteractionEnabled = YES; // this is also written in my viewDidLoad method 
    [[_card.layer presentationLayer] hitTest:origini]; // not really sure what this does 
    [self.view addSubview:_card]; 

    int randomSpeed = rand() % 20; 
    int randomDelay = rand() % 2; 
    [UIView animateWithDuration:randomSpeed + 10 
          delay: randomDelay + 4 
         options:UIViewAnimationOptionAllowUserInteraction // here is the method that I thought would allow me to interact with the moving cards. Not sure why I can't 
        animations: ^{ 
         _card.frame = cardFramei; 
        } 
        completion:NULL]; 
    } 
} 

注意下面的方法是我把CALayer和命中測試信息。我不確定我是否正確地做到了這一點。

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

UITouch *t = [touches anyObject]; 
UIView *myTouchedView = [t view]; 
CGPoint thePoint = [t locationInView:self.view]; 

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

if([_card.layer.presentationLayer hitTest:thePoint]) 
{ 
    NSLog(@"You touched a Shape!"); // This only logs when I touch a non-moving shape 
} 
else{ 
    NSLog(@"backgound touched"); // this logs when I touch the background or an moving shape. 
} 


if(myTouchedView == _card) 
{ 
    NSLog(@"Touched a card"); 
    _boolHasCard = YES; 
} 
    else 
    { 
     NSLog(@"Didn't touch a card"); 
     _boolHasCard = NO; 
    } 


} 

我想要下面的方法來移動形狀。它只適用於不移動的形狀。許多答案表示要問問卡片來自哪一類。截至目前,我所有的同類卡片(viewController類)。當試圖讓卡片成爲他們自己的班級時,我無法在主背景控制器上顯示該視圖。我是否必須爲不同的班級準備不同的卡片才能工作,或者我可以在不需要這樣做的情況下工作嗎?

-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
UITouch *touch = [[event allTouches] anyObject]; 
if([touch view]==self.card) 
{ 
    CGPoint location = [touch locationInView:self.view]; 
    self.card.center=location; 
} 
} 

如果用戶開始移動然後提起卡片,則下一個方法將重置卡片的移動。

-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
if(_boolHasCard == YES) 
{ 

[UIView animateWithDuration:3 
         delay: 0 
        options:UIViewAnimationOptionAllowUserInteraction 
       animations: ^{ 
        CGRect newCardOrigin = CGRectMake(1200,_card.center.y - 92/2, 92, 87); 
        _card.frame = newCardOrigin; 
       } 
       completion:NULL]; 
    } 


} 

@end 
+0

看看我的回答和討論[這裏](http://stackoverflow.com/a/15682277/1756131)。它可能不是特定於你的需要,但我認爲它會給它一些啓示。 –

+0

我查出了那個代碼,我只能讓火箭來回移動。當我點擊它時什麼都沒有發生。它不停止。它不會消失。 – iOSAppGuy

回答

2

簡短的回答是,你不能。

Core Animation實際上並沒有沿着動畫路徑移動對象。他們移動對象圖層的表示層。

動畫開始的那一刻,系統認爲對象在它的目的地。

如果您想使用Core Animation,則無法解決此問題。

你有幾個選擇。

  1. 您可以設置一個CADisplayLink您的視圖控制器上,並推出自己的動畫,在那裏你有少量的移動你的看法中心每次調用顯示鏈接。這可能會導致糟糕的表現和動態動畫,但是如果您要動畫很多對象。

  2. 您可以將手勢識別器添加到包含所有動畫的父視圖中,然後在主視圖的演示視圖上使用圖層命中測試來確定哪個動畫圖層被輕敲,然後獲取該圖層的委託,這將成爲你動畫的視角。我在github上有一個項目,展示瞭如何做第二種技術。它只能檢測單個移動視圖上的點擊,但它會向您顯示基本信息:Core Animation demo project on github

(上投票,如果你發現這個職位有幫助很喜歡)

+0

謝謝你的洞察!我調整了我的代碼,讓手勢識別器與飛行中的動畫進行交互。我仍然無法獲得更多的視圖進行交互。我必須設置一系列視圖(或圖層)並循環遍歷它們以使代碼適用於每個視圖? – iOSAppGuy

1

它看起來對我說,你的問題是真正與如何協調空間之間的點轉換隻是一個不完全的瞭解。按預期工作這正是代碼:

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 

    CGPoint endPoint = CGPointMake([[self view] bounds].size.width, 
           [[self view] bounds].size.height); 

    CABasicAnimation *animation = [CABasicAnimation 
             animationWithKeyPath:@"position"]; 
    animation.fromValue = [NSValue valueWithCGPoint:[[_imageView layer] position]]; 
    animation.toValue = [NSValue valueWithCGPoint:endPoint]; 
    animation.duration = 30.0f; 

    [[_imageView layer] addAnimation:animation forKey:@"position"]; 
} 

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    UITouch *t = [touches anyObject]; 
    CGPoint thePoint = [t locationInView:self.view]; 

    thePoint = [[_imageView layer] convertPoint:thePoint 
             toLayer:[[self view] layer]]; 

    if([[_imageView layer].presentationLayer hitTest:thePoint]) 
    { 
    NSLog(@"You touched a Shape!"); 
    } 
    else{ 
    NSLog(@"backgound touched"); 
    } 

} 

通知特別行:「你摸了形」

thePoint = [[_imageView layer] convertPoint:thePoint 
             toLayer:[[self view] layer]]; 

當我在層圖像視圖挖掘,而它的動畫,我得到在控制檯窗口中,當我點擊它時,我會看到「背景」。這就是你想要的嗎?

這裏有一個sample project on Github

UPDATE

爲了幫助你的跟進問題的意見,我寫的代碼的touchesBegan不同的一點。想象一下,當您創建它們時,您已將所有圖像視圖添加到數組(巧妙地命名爲imageViews)。你會改變你的代碼看起來是這樣的:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
{ 
    UITouch *t = [touches anyObject]; 
    CGPoint thePoint = [t locationInView:self.view]; 

    for (UIImageView *imageView in [self imageViews]) { 
    thePoint = [[imageView layer] convertPoint:thePoint 
             toLayer:[[self view] layer]]; 

    if([[imageView layer].presentationLayer hitTest:thePoint]) { 
     NSLog(@"Found it!!"); 
     break; // No need to keep iterating, we've found it 
    } else{ 
     NSLog(@"Not this one!"); 
    } 
    } 
} 

我不知道有多貴,這是,所以你可能剖析它,但它應該做你期待什麼。

+0

非常好!這正是我所期待的。如果我有多個部分重疊的運動形狀呢?這是否會按預期返回圖層?例如:如果一個移動的三角形與移動的正方形略有重疊,並且我在重疊過程中觸摸了三角形,我可以說「你觸摸了三角形」。然後當觸摸廣場的可見部分時,它會「你觸摸廣場!」。 – iOSAppGuy

+0

是的。這正是它的工作原理。如果你閱讀了關於測試核心動畫層的命中文檔,它說*返回包含指定點的層次結構(包括它本身)中接收者的最遠後代。* https://developer.apple.com/library/ mac/documentation/graphicsimaging/reference/CALayer_class/Introduction/Introduction.html#// apple_ref/occ/instm/CALayer/hitTest: –

+0

當嘗試以編程方式將其他_imageView添加到應用程序時,我可能會做錯某些事情。我這樣做:[[_imageView alloc] initWithFrame:CGRectMake(100,100,100,100)];然後我添加圖像_imageView.image = [UIImage imageName:@「newImage.png」]。然後我將它添加到視圖的子視圖[self.view addSubview:_imageView]。當我點擊它說「背景點擊」。我有2個移動圖像(你的和我的)。你的說:「你摸了一個形狀!」我說「背景感動」。爲什麼會這樣呢? – iOSAppGuy