我想在用户触摸位置的视图中添加一个UIImageView
,并在用户握住手指时使UIImageView
生长。想想一个呼吸的人被炸毁。我希望UIImageView的中心在增长时保留在用户的触摸位置。
我认为最好的方法是UILongPressGestureRecognizer
并写下以下内容。除了视觉效果有些断断续续和笨拙,这确实可以按照我的计划工作。
有什么方法可以使UIImageView的大小动画,直到UILongPressGestureRecognizer
调用UIGestureRecognizerStateEnded
?
或,有更好的方法可以完全做这件事吗?
在.h: CGPoint longPressLocation;
.m:
- (IBAction) handleInflation:(UILongPressGestureRecognizer *) inflateGesture {
longPressLocation= [inflateGesture locationInView:self.view];
switch (inflateGesture.state) {
case UIGestureRecognizerStateBegan:{
NSLog(@"Long press Began .................");
inflateTimer = [NSTimer scheduledTimerWithTimeInterval:.4 target:self selector:@selector(inflate) userInfo:nil repeats:YES];
UIImage *tempImage=[UIImage imageNamed:@"bomb.png"];
UIImageView *inflatableImageView = [[UIImageView alloc] initWithFrame:CGRectMake(longPressLocation.x-tempImage.size.width/2,
longPressLocation.y-tempImage.size.height/2,
tempImage.size.width, tempImage.size.height)];
inflatableImageView.image = tempImage;
[bonusGame addSubview:inflatableImageView];
inflatable=inflatableImageView;
}
break;
case UIGestureRecognizerStateChanged:{
NSLog(@"Long press Changed .................");
}
break;
case UIGestureRecognizerStateEnded:{
NSLog(@"Long press Ended .................");
[inflateTimer invalidate];
}
break;
default:
break;
}
}
-(void)inflate{
inflatable.frame=CGRectMake(inflatable.frame.origin.x,inflatable.frame.origin.y , inflatable.bounds.size.width+15, inflatable.bounds.size.height+15);
inflatable.center=longPressLocation;
}
最终工作代码:
- (IBAction) handleInflation:(UILongPressGestureRecognizer *) inflateGesture {
inflateGesture.minimumPressDuration = .01;
longPressLocation= [inflateGesture locationInView:self.view];
switch (inflateGesture.state) {
case UIGestureRecognizerStateBegan:{
NSLog(@"Long press Began .................");
inflateStart = [NSDate date];
inflateDisplayLink = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:self selector:@selector(inflate)];
[inflateDisplayLink setFrameInterval:1];
[inflateDisplayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
UIImage *tempImage=[UIImage imageNamed:@"bomb.png"];
UIImageView *inflatableImageView = [[UIImageView alloc] initWithFrame:CGRectMake(longPressLocation.x-tempImage.size.width/2,
longPressLocation.y-tempImage.size.height/2,
tempImage.size.width, tempImage.size.height)];
inflatableImageView.image = tempImage;
[bonusGame addSubview:inflatableImageView];
inflatable=inflatableImageView;
}
break;
case UIGestureRecognizerStateChanged:{
NSLog(@"Long press Changed .................");
}
break;
case UIGestureRecognizerStateEnded:{
NSLog(@"Long press Ended .................");
[inflateDisplayLink invalidate];
}
break;
default:
break;
}
}
-(void)inflate{
NSDate *inflateEnd = [NSDate date];
NSTimeInterval inflateInterval;
inflateInterval = ([inflateEnd timeIntervalSince1970] - [inflateStart timeIntervalSince1970])*25;
inflatable.frame=CGRectMake(inflatable.frame.origin.x,
inflatable.frame.origin.y ,
inflatable.bounds.size.width+inflateInterval,
inflatable.bounds.size.height+inflateInterval);
inflatable.center=longPressLocation;
if(inflatable.bounds.size.width>200){
[inflateDisplayLink invalidate];
}
}
计时器可能不会平滑。相反,请查看CADisplayLink
,每当设备的屏幕重新绘制(〜60Hz)时,它将提供代表回调,因此您将获得调整气球尺寸的每一帧机会。
要考虑的另一件事是,刷新之间的时间不是恒定的,它可能比上次刷新时要慢得多,因此,如果您每次收到回调时将大小增加一个常数15,则动画可能看起来不流畅。
要打击这一点,当您启动动画时,请使用时间戳并握住它,然后当您夸大气球时,请使用另一个时间戳,确定现在和最后一个重新绘制的差异,然后将差异乘以一定的值,这将确保恒定的平滑尺寸增长 - 这称为 timeStep 。
https://developer.apple.com/library/ios/documentation/quartzcore/reference/cadisplaylink_classref/reference/reference/Reference.html
在这里变得有创意,但我认为这可能有效:您启动一个动画,将图像框架从其当前尺寸到最大尺寸的动画动画。
一旦检测到长按手势,请立即开始动画。
如果手势结束,请从动画视图/图像的presentationLayer
获取当前的帧大小,并通过使用UIViewAnimationOptionBeginFromCurrentState
启动新动画将视图/图像的帧更新为该大小,以便旧动画停止。
应该给您一个平稳生长的气球。
尝试这个....
imageView = [[UIImageView alloc] initWithFrame:(CGRectMake(120, 100, 30, 30))];
imageView.backgroundColor = [UIColor redColor];
[self.view addSubview:imageView];
imageView.userInteractionEnabled = TRUE;
UILongPressGestureRecognizer *g = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
[g setMinimumPressDuration:0.001];
[imageView addGestureRecognizer:g];
并添加这些方法
-(void)longPress:(UITapGestureRecognizer *)t
{
if (t.state == UIGestureRecognizerStateBegan)
{
[timer invalidate];
timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(makeIncrc) userInfo:nil repeats:TRUE];
}
else if (t.state == UIGestureRecognizerStateEnded || t.state == UIGestureRecognizerStateCancelled)
{
[timer invalidate];
timer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(makeDec) userInfo:nil repeats:TRUE];
}
}
-(void)makeIncrc
{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationCurve:(UIViewAnimationCurveLinear)];
CGRect frame = imageView.frame;
frame.origin.x = frame.origin.x - 5;
frame.origin.y = frame.origin.y - 5;
frame.size.width = frame.size.width + 10;
frame.size.height = frame.size.height + 10;
imageView.frame = frame;
[UIView commitAnimations];
}
-(void)makeDec
{
if (imageView.frame.size.width < 20 || imageView.frame.size.height < 20)
{
[timer invalidate];
}
else
{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationCurve:(UIViewAnimationCurveLinear)];
CGRect frame = imageView.frame;
frame.origin.x = frame.origin.x + 5;
frame.origin.y = frame.origin.y + 5;
frame.size.width = frame.size.width - 10;
frame.size.height = frame.size.height - 10;
imageView.frame = frame;
[UIView commitAnimations];
}
}
这是一个快速版本。为了避免失控的通货膨胀,我必须用"暂停"替换无效的()呼叫。
var inflateDisplayLink: CADisplayLink?
var inflateStart: NSDate!
var longPressLocation: CGPoint!
var inflatable: UIImageView!
func handleInflation(inflateGesture: UILongPressGestureRecognizer) {
longPressLocation = inflateGesture.locationInView(self.view)
let imageView = inflateGesture.view as! UIImageView
switch (inflateGesture.state) {
case .Began:
println("Long press Began .................")
inflateStart = NSDate()
let tempImageView = UIImageView(image: imageView.image)
tempImageView.contentMode = .ScaleAspectFit
tempImageView.frame = imageView.frame
self.view.addSubview(tempImageView)
inflatable = tempImageView
if inflateDisplayLink == nil {
inflateDisplayLink = CADisplayLink(target: self, selector: Selector("inflate"))
inflateDisplayLink!.frameInterval = 1
inflateDisplayLink!.addToRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode)
} else {
inflateDisplayLink!.paused = false
}
break
case .Changed:
println("Long press Changed .................")
break
case .Ended:
println("Long press Ended .................")
inflateDisplayLink!.paused = true
break
default:
break
}
}
func inflate() {
var inflateEnd = NSDate()
// Convert from Double to CGFloat, due to bug (?) on iPhone5
var inflateInterval: CGFloat = CGFloat((Double(inflateEnd.timeIntervalSince1970) - Double(inflateStart.timeIntervalSince1970))) * 5.0
inflatable.frame = CGRectMake(inflatable.frame.origin.x, inflatable.frame.origin.y, inflatable.bounds.size.width + inflateInterval, inflatable.bounds.size.height + inflateInterval)
inflatable.center = longPressLocation.center
if inflatable.bounds.size.width > 200 {
inflateDisplayLink!.paused = true
}
}