在研究“如何在移动的UIImageView上检测到触摸事件?”时我遇到了几个答案,我试图将它们应用到我的应用程序中。我遇到的任何东西似乎都没有用。我会解释我正在尝试做什么,然后发布我的代码。任何想法,建议,意见或答案都表示赞赏!
我的应用有几张卡片从左到右悬浮在屏幕上。这些卡是各种颜色的,游戏的目的是将卡拖到它们相似颜色的相应容器上。如果用户没有足够快地触摸并拖动卡片,则卡片将从屏幕上漂移并且点将丢失。正确容器中包含的卡越多,得分越高。
我使用核心动画编写代码让我的卡片从左向右浮动。这有效。但是,当试图触摸卡并将其拖向它的容器时,它无法正确检测到我正在触摸卡的UIImageView。
为了测试我是否正确实现移动卡的代码,我还写了一些代码允许移动非移动卡。在这种情况下,我的触摸被检测并相应地起作用。
为什么我只能与固定卡互动?经过相当多的研究后,似乎是代码:
options:UIViewAnimationOptionAllowUserInteraction
是让我的移动UIImages被检测到的关键因素。但是我试过这似乎没有任何影响。
我可能做错的另一个关键因素是没有正确使用正确的表示层。我已将这样的代码添加到我的项目中,而且我也只处理非移动对象:
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 :(得分:2)
简短的回答是,你做不到。
Core Animation实际上并不沿着动画路径移动对象。他们移动对象图层的表示层。
动画开始的那一刻,系统认为对象就在它的目的地。
如果您想使用Core Animation,则无法解决此问题。
你有几个选择。
您可以在视图控制器上设置CADisplayLink并滚动自己的动画,在每次调用显示链接时,您可以将视图中心移动一小部分。如果您要为很多对象设置动画,这可能会导致性能不佳和动画不稳定。
您可以将手势识别器添加到包含所有动画的父视图中,然后在paren't视图的演示视图上使用图层命中测试来确定触摸了哪个动画层,然后获取该图层的委托,这将是你动画的视图。我在github上有一个项目,展示了如何做第二种技术。它仅检测单个移动视图上的点按,但它会显示基本信息:Core Animation demo project on github。
(如果你发现这篇文章很有帮助,那么总是赞赏)
答案 1 :(得分: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]];
当我在设置动画时点击图层图像视图时,我会看到“你碰到了一个形状!”在控制台窗口中,当我点击它时,我得到“背景触摸”。这就是你想要的吗?
<强>更新强>
为了帮助您在评论中提出跟进问题,我写了一些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!");
}
}
}
我不确定这是多么昂贵,所以你可能需要对它进行分析,但它应该做你期望的事情。