【问题标题】:Bounce UIImageView back when dragged off screen拖出屏幕时弹回 UIImageView
【发布时间】:2012-11-17 02:57:05
【问题描述】:

我需要的是,当 UIImageView 被拖离屏幕时,它会在松开时弹回。我让它在左侧和顶部工作,这就是我正在做的。

    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {          

        if (!CGRectContainsPoint(self.view.frame, imageView.frame.origin)){  

            CGFloat newX = 0.0f;
            CGFloat newY = 0.0f;

            // If off screen upper and left

            if (imageView.frame.origin.x < 0.0f){
                CGFloat negX = imageView.frame.origin.x * -1;
                newX = negX;
            }else{
                newX = imageView.frame.origin.x;
            }

            if (imageView.frame.origin.y < 0.0f){
                CGFloat negY = imageView.frame.origin.y * -1;
                newY = negY;
            }else{
                newY = imageView.frame.origin.y;
            }


            CGRect newPoint = CGRectMake(newX, newY, imageView.frame.size.width, imageView.frame.size.height);

            [UIView beginAnimations:@"BounceAnimations" context:nil];
            [UIView setAnimationDuration:.5];
            [letterOutOfBounds play];
            [imageView setFrame:newPoint];

            [UIView commitAnimations];

        }
    }
}

所以我想在右侧和底部实现相同的效果。但我一直坚持这一点。有什么想法吗?

【问题讨论】:

    标签: objective-c ios uiimageview uitouch


    【解决方案1】:

    下面这样的怎么样?

    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    
        UIImageView *imageView = nil;
    
        BOOL moved = NO;
        CGRect newPoint = imageView.frame;
    
        // If off screen left
    
        if (newPoint.origin.x < 0.0f){
            newPoint.origin.x *= -1.0;
            moved = YES;
        }
    
        // if off screen up
    
        if (newPoint.origin.y < 0.0f){
            newPoint.origin.y *= -1.0;
            moved = YES;
        }
    
        // if off screen right
    
        CGFloat howFarOffRight = (newPoint.origin.x + newPoint.size.width) - imageView.superview.frame.size.width;
        if (howFarOffRight > 0.0)
        {
            newPoint.origin.x -= howFarOffRight * 2;
            moved = YES;
        }
    
        // if off screen bottom
    
        CGFloat howFarOffBottom = (newPoint.origin.y + newPoint.size.height) - imageView.superview.frame.size.height;
        if (howFarOffBottom > 0.0)
        {
            newPoint.origin.y -= howFarOffBottom * 2;
            moved = YES;
        }
    
        if (moved)
        {
            [UIView beginAnimations:@"BounceAnimations" context:nil];
            [UIView setAnimationDuration:.5];
            [letterOutOfBounds play];
            [imageView setFrame:newPoint];
    
            [UIView commitAnimations];
        }
    }
    

    当我阅读您的代码时,“如果离开左侧,将其移回视图的距离与离开屏幕相同的距离”的逻辑。老实说,这对我来说不太有意义(为什么,当弹回时,坐标是否取决于它离屏幕多远),但我试图在“离屏右侧”中尊重这一点,并且“离屏底部”逻辑。显然我的逻辑是使用imageViewsuperview 来确定包含视图的宽度,但如果这不合适,请将其替换为任何内容。

    编辑:

    我个人使用手势识别器来做这些事情,例如:

    UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
    [self.imageView addGestureRecognizer:pan];
    self.imageView.userInteractionEnabled = YES;
    

    因此,动画移动图像的手势识别器将是:

    - (void)handlePan:(UIPanGestureRecognizer *)gesture
    {
        static CGRect originalFrame; // you could make this an ivar if you want, but just for demonstration purposes
    
        if (gesture.state == UIGestureRecognizerStateBegan)
        {
            originalFrame = self.imageView.frame;
        }
        else if (gesture.state == UIGestureRecognizerStateChanged)
        {
            CGPoint translate = [gesture translationInView:gesture.view];
    
            CGRect newFrame = originalFrame;
    
            newFrame.origin.x += translate.x;
            newFrame.origin.y += translate.y;
    
            gesture.view.frame = newFrame;
        }
        else if (gesture.state == UIGestureRecognizerStateEnded || gesture.state == UIGestureRecognizerStateCancelled)
        {
            CGRect newFrame = gesture.view.frame;
    
            newFrame.origin.x = fmaxf(newFrame.origin.x, 0.0);
            newFrame.origin.x = fminf(newFrame.origin.x, gesture.view.superview.bounds.size.width - newFrame.size.width);
    
            newFrame.origin.y = fmaxf(newFrame.origin.y, 0.0);
            newFrame.origin.y = fminf(newFrame.origin.y, gesture.view.superview.bounds.size.height - newFrame.size.height);
    
            // animate how ever you want ... I generally just do animateWithDuration
    
            [UIView animateWithDuration:0.5 animations:^{
                gesture.view.frame = newFrame;
            }];
        }
    }
    

    或者,如果您想要一个手势识别器,首先只是防止将图像拖出屏幕,它会是:

    - (void)handlePan:(UIPanGestureRecognizer *)gesture
    {
        static CGRect originalFrame;
    
        if (gesture.state == UIGestureRecognizerStateBegan)
        {
            originalFrame = self.imageView.frame;
        }
        else if (gesture.state == UIGestureRecognizerStateChanged)
        {
            CGPoint translate = [gesture translationInView:gesture.view];
    
            CGRect newFrame = originalFrame;
    
            newFrame.origin.x += translate.x;
            newFrame.origin.x = fmaxf(newFrame.origin.x, 0.0);
            newFrame.origin.x = fminf(newFrame.origin.x, gesture.view.superview.bounds.size.width - newFrame.size.width);
    
            newFrame.origin.y += translate.y;
            newFrame.origin.y = fmaxf(newFrame.origin.y, 0.0);
            newFrame.origin.y = fminf(newFrame.origin.y, gesture.view.superview.bounds.size.height - newFrame.size.height);
    
            gesture.view.frame = newFrame;
        }
    }
    

    顺便说一句,在 iOS 7 中,您可以通过使用带有 usingSpringWithDampeninginitialSpringVelocity 参数的新 animationWithDuration 来让图像视图的动画回到其原始位置:

    [UIView animateWithDuration:1.0
                          delay:0.0
         usingSpringWithDamping:0.3
          initialSpringVelocity:0.1
                        options:0
                     animations:^{
                         // set the new `frame` (or update the constraint constant values that
                         // will dictate the `frame` and call `layoutViewsIfNeeded`)
                     }
                     completion:nil];
    

    或者,在iOS7中,你也可以使用UIKit Dynamics添加一个UISnapBehavior

    self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
    self.animator.delegate = self;
    
    UISnapBehavior *snap = [[UISnapBehavior alloc] initWithItem:self.viewToAnimate snapToPoint:CGPointMake(self.viewToAnimate.center.x, self.view.frame.size.height - 50)];
    
    // optionally, you can control how much bouncing happens when it finishes, e.g., for a lot of bouncing:
    //
    // snap.damping = 0.2;
    
    // you can also slow down the snap by adding some resistance
    //
    // UIDynamicItemBehavior *resistance = [[UIDynamicItemBehavior alloc] initWithItems:@[self.viewToAnimate]];
    // resistance.resistance = 20.0;
    // resistance.angularResistance = 200.0;
    // [self.animator addBehavior:resistance];
    
    [self.animator addBehavior:snap];
    

    【讨论】:

    • 效果很好,我遇到的唯一问题是 self.view 在横向时给出纵向尺寸。 CGRectContainsRect(self.view.frame, imageView.frame)
    • 旋转总是一个烦人的问题。顺便说一句,如果我的回答对你有用,请接受,谢谢。
    • @Jonathan 我的代码没有使用self.view.frame,所以我不确定我是否在关注你。我正在使用imageView.superview.frame,但你是说即使在横向时也会返回纵向尺寸?
    • @Rob 对不起,我不清楚,但它在横向时返回纵向尺寸
    • @Rob 这种看起来很复杂,你有什么更好的办法将 UIImageView 保留在视图中,也许可以让他们甚至不能拖掉它?
    【解决方案2】:

    我认为最简单的方法是检查您的imageView 是否已超出您的self.view

    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {  
        if (!CGRectContainsRect(self.view.frame, imageView.frame)){
            // Your animation to bounce.
        }
    }
    

    【讨论】:

    • 我认为问题不仅在于如何确定图像是否已移动到屏幕外的位置,还在于如何确定新位置。
    猜你喜欢
    • 1970-01-01
    • 2021-08-23
    • 1970-01-01
    • 2012-10-22
    • 1970-01-01
    • 1970-01-01
    • 2011-02-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多