简体   繁体   中英

UIPanGestureRecognizer - move view instantly

All I need it to move some view around based on pan gesture. The problem is that it doesn't happen instantly, just like Apple Maps, if I put down my finger on one point, and move it fast to any direction, the view will move with a delay, meaning I will be able to see the point that I put my finger on, and that is what I don't want.

Maybe it is impossible due to hardware limitations since in the simulator it works fine. Or maybe there is a better way that I don't know.

Thank you.


- (IBAction)pan:(UIPanGestureRecognizer *)sender 
{
    CGPoint center = [sender locationInView:sender.view];
    self.myView.center = center; 
}

When I first answered, I was presuming that there was something complicated about the view being dragged (eg a large CALayer shadow, which can be computationally expensive). Hence my original answer below. But in a subsequent exchange of comments, it has been discovered that one of the buttons had an pulsing animation, which is more likely to be the problem. The animation should be suspended during the dragging of the view if the dragging performance is not acceptable. Thus:

#import <QuartzCore/QuartzCore.h>

- (IBAction)pan:(UIPanGestureRecognizer *)gesture
{
    static CGPoint originalCenter;

    if (gesture.state == UIGestureRecognizerStateBegan)
    {
        originalCenter = gesture.view.center;
        [self pauseLayer:gesture.view.layer];
    }
    else if (gesture.state == UIGestureRecognizerStateChanged)
    {
        CGPoint translate = [gesture translationInView:gesture.view.superview];
        gesture.view.center = CGPointMake(originalCenter.x + translate.x, originalCenter.y + translate.y);
    }
    else if (gesture.state == UIGestureRecognizerStateEnded ||
             gesture.state == UIGestureRecognizerStateFailed ||
             gesture.state == UIGestureRecognizerStateCancelled)
    {
        [self resumeLayer:gesture.view.layer];
    }
}

-(void)pauseLayer:(CALayer*)layer
{
    CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
    layer.speed = 0.0;
    layer.timeOffset = pausedTime;
}

-(void)resumeLayer:(CALayer*)layer
{
    CFTimeInterval pausedTime = [layer timeOffset];
    layer.speed = 1.0;
    layer.timeOffset = 0.0;
    layer.beginTime = 0.0;
    CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
    layer.beginTime = timeSincePause;
}

Clearly, this can be combined with the rasterization of the image, discussed below, but I would try suspending the animation, like above, first.


Original answer:

If your view being dragged is at all complicated, you could try rasterizing it.

  1. Add QuartzCore.framework to your target's "Link binary with libraries" settings.

  2. And then adjust the source to rasterize accordingly.

Such as:

#import <QuartzCore/QuartzCore.h>

- (IBAction)pan:(UIPanGestureRecognizer *)gesture
{
    static CGPoint originalCenter;

    if (gesture.state == UIGestureRecognizerStateBegan)
    {
        originalCenter = gesture.view.center;
        gesture.view.layer.shouldRasterize = YES;
    }
    if (gesture.state == UIGestureRecognizerStateChanged)
    {
        CGPoint translate = [gesture translationInView:gesture.view.superview];
        gesture.view.center = CGPointMake(originalCenter.x + translate.x, originalCenter.y + translate.y);
    }
    if (gesture.state == UIGestureRecognizerStateEnded ||
        gesture.state == UIGestureRecognizerStateFailed ||
        gesture.state == UIGestureRecognizerStateCancelled)
    {
        gesture.view.layer.shouldRasterize = NO;
    }
}

As an aside, I'd suggest saving the originalCenter like this code does, so that if you grab the view being dragged a little off center, it won't jump jarringly on you.

Try disabling animations when you set the new value for the center point.

- (IBAction)pan:(UIPanGestureRecognizer *)sender 
{
    CGPoint center = [sender locationInView:sender.view];
    [CATransaction begin];
    [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
    self.myView.center = center; 
    [CATransaction commit];
}

If that helps you could try to smooth it with faster animation.

You could also try to disable the animations as described here: Explicitly disabling UIView animation in iOS4+

Shortly:

- (IBAction)pan:(UIPanGestureRecognizer *)sender 
{
    CGPoint center = [sender locationInView:sender.view];
    [UIView setAnimationsEnabled:NO];
    self.myView.center = center; 
    [UIView setAnimationsEnabled:YES];
}

Once you manage to disable all animations during the repositioning, it's up to the speed of the hardware and your code.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM