Autolayout, UIDynamics and animations
animation, autolayout, ios, uikit-dynamics
Solution
Well, similar behavior could be achieved with `UIPanGestureRecognizer` + `[UIView animateWithDuration:animations:]`. Yes, you set leading space constraint and change it according to `UIPanGestureRecognizer` state. Remember that you need to set final constraints only (define final position of a slider). Intermediate animation positions are calculated for you. For the slider we have default left position and activated middle position.
For view rotation we can use `transform` property of `UIView`.
Autolayout constraints in IB:
Setting animation options (`UIViewAnimationOptionCurveEaseOut` animation curve) could give a feel of bounce effect. `UIPanGestureRecognizer` code (omit instance variables declaration, because their names are self-explanatory):
- (IBAction)onPan:(UIPanGestureRecognizer*)sender
{
switch (sender.state) {
case UIGestureRecognizerStateBegan:
_startOffset = self.leadingSpace.constant;
_maxOffset = self.slider.superview.frame.size.width
- kHorizontalPadding
- self.slider.frame.size.width;
break;
case UIGestureRecognizerStateChanged: {
CGFloat offset = _startOffset + [sender translationInView:self.slider.superview].x;
offset = MIN(offset, _maxOffset);
self.leadingSpace.constant = offset;
break;
}
case UIGestureRecognizerStateEnded: {
CGFloat offset = _startOffset + [sender translationInView:sender.view.superview].x;
UIColor *bgColor = [UIColor lightGrayColor];
CGFloat rotation = 0;
if (offset < _maxOffset) {
offset = kHorizontalPadding;
}
else {
offset = (_maxOffset + kHorizontalPadding)/2;
bgColor = [UIColor redColor];
rotation = M_PI_2;
}
self.leadingSpace.constant = offset;
[UIView
animateWithDuration:.5
delay:0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
[self.slider layoutIfNeeded];
self.slider.backgroundColor = bgColor;
self.slider.transform = CGAffineTransformMakeRotation(rotation);
} completion:nil];
break;
}
default:
break;
}
}
Animation result with `UIViewAnimationOptionCurveLinear` (capture simulator):
Animation result with `UIViewAnimationOptionCurveEaseOut` (capture simulator):
UIDynamics
With UIDynamics things become more complicated. Good starting point is Ray Wenderlich UIKit Dynamics Tutorial.
For bouncing slider we could add following behaviors:
- `UIGravityBehavior` which pulls a slider to start position. We need to change `angle` property to direct gravity force to the left.
- `UICollisionBehavior` which defines left and right edges of allowed movements. `translatesReferenceBoundsIntoBoundary` property will be useful if we treat parent view as boundary. Also we need to add extra boundary to stop slider in the middle using `addBoundaryWithIdentifier:fromPoint:toPoint` (or bezier path).
- `UIDynamicItemBehavior` to change `elasticy` and possibly `resistance` properties to configure bounce and acceleration respectively.
- Possibly `UIPushBehavior` in conjunction with recognizer's `velocityInView:` to specify slider velocity when a user releases a slider
- Possibly `UISnapBehavior` as an alternative to `UIGravityBehavior`
Problem
I'm pretty new to auto layout and I'm confused about how to animate views. I read a lot, and I know you must hold to the constraints, edit it, and wrap the `layoutIfNeeded` in an `UIView` animation block. But when it comes to do it, I'm a little lost. I'd love if someone could explain me how this animation is done for example. I think it probably uses a `UIPanGestureRecognizer` to change the `constant` of the leading space to container constraint, but it probably uses UIDynamics (for the bounce effect at the right ?).