【问题标题】:Grow a UIImageView while UILongPressGestureRecognizer active在 UILongPressGestureRecognizer 处于活动状态时增长 UIImageView
【发布时间】:2014-02-05 13:03:37
【问题描述】:

我想在用户触摸位置的视图中添加一个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];
    }
}

【问题讨论】:

  • 效率如何?这是一个整洁的小解决方案!
  • @homelesspeoplecancode 它非常适合我的需求(我女儿的一个简单的气球爆破游戏),她能够在屏幕上创建大约 1000 个气球而没有任何问题。虽然现在在 Swift 中可能有更好的方法来做到这一点:)

标签: ios iphone objective-c uiimageview uiviewanimation


【解决方案1】:

计时器可能不流畅。相反,请查看CADisplayLink,它会在设备屏幕重绘(~60hz)时提供一个委托回调,因此您将获得每帧调整气球大小的机会。

要考虑的另一件事是刷新之间的时间不是恒定的,它可能比上次刷新时慢很多,所以如果每次收到回调时将大小增加一个常数 15,那么动画可能看起来不流畅。

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

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

【讨论】:

  • 完美,根据您的回答实现,我添加了上面的代码以防您好奇并帮助他人,谢谢!
【解决方案2】:

在这里发挥创意,但我认为这可能有效: 您启动一个动画,将图像帧从其当前尺寸变为最大尺寸。

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

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

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

【讨论】:

    【解决方案3】:

    试试这个....

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

    【讨论】:

    • 这比我的要好,在给定的速度下运行良好,但在加速以满足我的需要时仍然会变得不稳定,但感谢您的帮助!
    • 您可以更改帧更新和计时器时间以获得流畅的动画
    【解决方案4】:

    这是一个 Swift 版本。为了避免失控的通货膨胀,我不得不将 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
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-05-13
      • 2013-09-12
      相关资源
      最近更新 更多