2
votes

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; 
}
2
- (IBAction)pan:(UIPanGestureRecognizer *)sender { CGPoint center = [sender locationInView:sender.view]; self.myView.center = center; }Rodrigo Ruiz
I'm sorry, I don't know how to keep indentation.Rodrigo Ruiz
What is on this view? If fairly complicated, you can rasterize and see if that fixes it.Rob
This view has only 2 UIImageView's (one of the UIImageView's is being animated, just scale, like pulsing). Basically myView is the same as that blue ball with pulsating circle that you see on maps for your current location. And what I want is move that ball around making it stays always below the user's finger. So it should never be possible to see the center of the ball when the user pans.Rodrigo Ruiz
The pulsing animation, while not a burden in standard operations, will have a material impact on dragging the whole thing. Try pausing the pulsing and see if the behavior improves. Even simple things like non-rasterized shadows can be surprisingly problematic. You need to simplify things (at least during the pan). Also see an example of rasterizing the view (but also pause the pulsing animation, too).Rob

2 Answers

6
votes

When I first answered, I was presuming that there was something complicated about the view being dragged (e.g. 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.

1
votes

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.