在UILongPressGestureRecognizer处于活动状态时生成UIImageView

时间:2014-02-05 13:03:38

标签: ios iphone objective-c uiimageview uiviewanimation

我想在用户触摸位置向我的视图添加UIImageView,并在用户按下手指时让UIImageView增长。想想一个气球被炸毁了。我希望UIImageView的中心在其成长过程中保持在用户的触摸位置。

我认为最好的方法是UILongPressGestureRecognizer并写下面的内容。除了视觉效果有些不稳定和笨拙之外,这确实有效。

UILongPressGestureRecognizer调用UIGestureRecognizerStateEnded之前,有没有办法让UIImageView的大小动画化?

或者,有没有更好的方法来完成这项工作?

在.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];
    }
}

4 个答案:

答案 0 :(得分:4)

计时器可能不顺畅。取而代之的是CADisplayLink,它会在设备的屏幕重绘(~60hz)时提供代表回调,这样您就可以获得每帧调整气球大小的机会。

要考虑的另一件事是刷新之间的时间不是恒定的,它可能比最后一次刷新时要慢得多,所以如果你每次收到回调时将大小增加一个常数15,那么动画似乎并不顺畅。

为了解决这个问题,当您开始动画时,请使用时间戳并按住它,然后当您为气球充气时,请使用另一个时间戳并确定现在和最后一次重绘之间的差异,然后将差值乘以某个值,这将是确保持续平滑的大小增长 - 这称为时间步长

https://developer.apple.com/library/ios/documentation/QuartzCore/Reference/CADisplayLink_ClassRef/Reference/Reference.html

答案 1 :(得分:2)

在这里发挥创意,但我认为这可行: 您启动动画,将图像帧从其当前大小设置为最大大小。

检测到长按手势后立即启动动画。

如果手势结束,请从动画视图/图像的presentationLayer获取当前帧大小,并通过使用UIViewAnimationOptionBeginFromCurrentState启动新动画将视图/图像的帧更新为该大小,以便旧动画将停止。

这应该会给你一个平稳增长的气球。

答案 2 :(得分:0)

试试这个......

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];
    }
}

答案 3 :(得分:0)

这是一个Swift版本。我不得不用&#34;暂停&#34;替换invalidate()调用。为了避免通货膨胀失控。

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
    }
}