Отскок UIImageView назад при перетаскивании с экрана
Что мне нужно, так это когда 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];
}
}
}
Поэтому я хотел бы добиться того же самого для правой и нижней сторон. Но я застрял на этом на некоторое время. Есть Идеи?2 ответа:
Как насчет чего-то вроде следующего?
Когда я читаю ваш код, логика "если слева, переместите его обратно в вид на то же расстояние, на котором он был вне экрана."Честно говоря, это не совсем имеет смысл для меня (почему, когда отскакивает назад, координата зависит от того, насколько далеко от экрана она была), но я пытался соблюдать это в логике "вне экрана справа" и "вне экрана снизу". Очевидно, моя логика использует- (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]; } }
superview
изimageView
для определения ширины содержащее представление, но если это не подходит, замените его тем, что есть.Редактировать:
Я лично делаю это с распознавателями жестов, такими как:
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 Вы можете дать анимация вида изображения обратно в исходное положение немного подпрыгивает с помощью новых
animationWithDuration
с параметрамиusingSpringWithDampening
иinitialSpringVelocity
:[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 для добавления
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];