Upgrade to Pro — share decks privately, control downloads, hide ads and more …

UIKit Dynamics - Paul Warren at iOSDevCamp Denver 2013

Emily
November 21, 2013

UIKit Dynamics - Paul Warren at iOSDevCamp Denver 2013

Double Encore's Paul Warren talks about UIKit Dynamics at iOSDevCamp Denver, November 16th, 2013.

Emily

November 21, 2013
Tweet

More Decks by Emily

Other Decks in Programming

Transcript

  1. UIKit Dynamics Whats and whys ! Overview of the API

    ! Dig into a custom example ! Effect tear-down
  2. UIKit Dynamics What is it ? “A composable, reusable, declarative,

    real- world inspired animation, and interaction system“ Apple describes it as: To put it another way: A Physics engine for UIKit
  3. UIKit Dynamics What is it for? Adds a sense of

    real-world movement Goes beyond Core Animation with collisions and forces Can include Attachments to other objects or Points Can really add some polish to the “feel” of the UI.
  4. UIKit Dynamics Where have you seen it? Apple uses it

    a lot in iOS7 Lock Screen camera Notification Center iMessage
  5. UIKit Dynamics How does it work? UIDynamicAnimator Class gives us

    access to the underlying physics engine We add attachments, collisions etc. though UIBehavior Classes The animator manipulates UIViews or other UIBehaviorItem types by modifying the Center or Transform properties The animator cycles through each iteration of movement until the objects come to rest
  6. UIKit Dynamics UIDynamicAnimator The animator is allocated with a Reference

    View which should also be the parent view of any items we want to animate. The animator continually calculates the impact of any active behaviors. ! UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
  7. UIKit Dynamics UIDynamicItem Protocol This identifies the objects that the

    animator can manipulate UIView & UICollectionViewLayoutAttributes adopt this protocol Defines only 3 Properties that we’re already very familiar with: • Bounds • Center • Transform We can adopt this in our classes to create custom Dynamic items
  8. UIKit Dynamics UIDynamicBehavoir Parent Class of all of the Behaviors

    Declares the Action property that can hold a block that is called for each iteration of the animation loop. Declares the Child Behavior properties and methods
  9. UIKit Dynamics UIGravityBehavior A simple and realistic gravity simulator Can

    be attached to multiple DynamicItems ! ! ! ! UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[self.square]]; ! [animator addBehavior:gravity];
  10. UIKit Dynamics UICollisionBehavior The simplest collision is between an item

    and it’s reference View’s Bounds. ! ! ! ! UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[self.square1]]; ! [animator addBehavior:gravity]; UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[self.square1]]; ! collisionBehavior.translatesReferenceBoundsIntoBoundary = YES; ! [animator addBehavior:collision];
  11. UIKit Dynamics UIAttachmentBehavoir The relationship between a dynamic item and

    an anchor point or another item. Attachment points can be offset ! UIAttachmentBehavior *attachment = [[UIAttachmentBehavior alloc] initWithItem:self.square1 offsetFromCenter:attachmentPoint attachedToAnchor:centerPoint]; ! [animator addBehavior:attachmentBehavior];
  12. UIKit Dynamics UIAttachmentBehavoir Make the attachment a spring Set either

    the frequency and/or the damping level ! ! attachmentBehavior.frequency = 1.0; ! attachmentBehavior.damping = 0.1;
  13. UIKit Dynamics UISnapBehavior ! Snap directly to any point. !

    UISnapBehavior *snap = [[UISnapBehavior alloc] initWithItem:self.square snapToPoint:point]; ! [self.animator addBehavior:snap]; !
  14. UIKit Dynamics UIPushBehavior - Instantaneous ! init with mode Set

    angle (radians) or pushDirection (CGVector)
 
 Set magnitude (points) ! UIPushBehavior *push = [[UIPushBehavior alloc] initWithItems:@[self.sqr] mode:UIPushBehaviorModeInstantaneous]; ! pushBehavior.angle = M_PI; ! pushBehavior.magnitude = 100.0; ! pushBehavior.pushDirection = CGVectorMake(100.0, 0.0); ! [animator addBehavior:push];
  15. UIKit Dynamics UIPushBehavior - Continuous init with continuous mode Acts

    as an accelerating force ! UIPushBehavior *push = [[UIPushBehavior alloc] initWithItems:@[self.sqr] mode:UIPushBehaviorModeContinuous]; ! pushBehavior.angle = M_PI; ! pushBehavior.magnitude = 100.0; ! pushBehavior.pushDirection = CGVectorMake(0.0, 100.0); ! [animator addBehavior:push];
  16. UIKit Dynamics UIItemBehavior Add behavior properties to Items • Density

    • Elasticity • Friction • Resistance • Angular Resistance ! self.itemBehavior = [[UIDynamicItemBehavior alloc] initWithItems:@[self.sqr]]; ! self.itemBehavior.elasticity = 0.5; ! [animator addBehavior:self.itemBehavior];
  17. UIKit Dynamics Custom Behavior - UIView Subclass Override Center property

    Add an Attachment with Frequency Add a downward PushBehavior Reuse dynamically computed values Draw a UIBeziercurve
  18. Dynamic Line View Controller - (void)viewDidLoad { [super viewDidLoad]; !

    self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; UIAttachmentBehavior *spring = [[UIAttachmentBehavior alloc] initWithItem:self.dynamicLine attachedToAnchor:self.view.center]; spring.frequency = 1.0; spring.damping = 0.1; [self.animator addBehavior:spring]; ! self.push = [[ UIPushBehavior alloc] initWithItems:@[self.dynamicLine] mode:UIPushBehaviorModeInstantaneous]; self.push.pushDirection = CGVectorMake(0, 100); self.push.magnitude = 200; self.push.active = NO; [self.animator addBehavior:self.push]; } ! - (IBAction)twang:(UIButton *)sender { self.push.active = YES; }
  19. Dynamic Line UIView Subclass @interface PRDDynamicLine () ! @property (nonatomic)

    CGFloat curveTop; ! @end ! @implementation PRDDynamicLine ! - (void)setCenter:(CGPoint)newCenter { self.curveTop = newCenter.y; [self setNeedsDisplay]; } ! - (CGPoint)center { return CGPointMake(self.bounds.size.width/2, self.curveTop); } ! - (void)drawRect:(CGRect)rect { CGFloat yPos = self.bounds.size.height/2.0; UIBezierPath *path = [UIBezierPath bezierPath]; [path moveToPoint:CGPointMake(0, yPos)]; [path addQuadCurveToPoint:CGPointMake(self.bounds.size.width, yPos) controlPoint:CGPointMake(self.bounds.size.width/2.0, yPos+self.curveTop)]; [path stroke]; } ! @end
  20. UIKit Dynamics Dynamic Image Viewer - TapBots TweetBot 3 Added

    Dynamic Image Viewer The image can be moved around but snaps back to place But if moved quickly or flicked, uses it’s momentum and spin to dismiss
  21. UIKit Dynamics How did they do that? UIView Subclass PanGestureRecognizer

    UIAttachmentBehavior fixed to TouchPoint PanGesture Velocity used to push off image Core Animation used to “spring” back
  22. Dynamic View Subclass @interface PRDDynamicView () <UICollisionBehaviorDelegate, UIDynamicAnimatorDelegate> ! @property

    (nonatomic, strong) UIDynamicAnimator *animator; @property (nonatomic, strong) UIAttachmentBehavior *attachmentBehavior; @property (assign) CGPoint oldCenter; @property (assign) UIOffset imageOffset; @property (nonatomic, strong) UIPanGestureRecognizer *panGesture; ! @end ! @implementation PRDDynamicView ! - (id)initWithCoder:(NSCoder *)coder { self = [super initWithCoder:coder]; if (self) { self.imageView = [[UIImageView alloc] initWithFrame:self.bounds]; self.userInteractionEnabled = YES; [self addSubview:self.imageView]; self.panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pannedGravitySquare:)]; [self addGestureRecognizer:self.panGesture]; self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self]; self.oldCenter = self.imageView.center; } return self; }
  23. Pan Gesture Selector - (IBAction)pannedGravitySquare:(UIPanGestureRecognizer *)sender { CGPoint position =

    [sender locationInView:[self.imageView superview]]; CGPoint offset = [sender locationInView:self.imageView]; self.imageOffset = UIOffsetMake(offset.x-self.imageView.bounds.size.width/2, offset.y-self.imageView.bounds.size.height/2); if (sender.state == UIGestureRecognizerStateBegan) { // The image offset and the position use different coordinates but must map to the // same point on the SquareView to get the effect we want self.attachmentBehavior = [[UIAttachmentBehavior alloc] initWithItem:self.imageView offsetFromCenter:self.imageOffset attachedToAnchor:position]; ! [self.animator addBehavior:self.attachmentBehavior]; } else if (sender.state == UIGestureRecognizerStateChanged) { // As the anchor point and the offset coincide the pan gesture appears to move the // imageView directly but this is actually handled by the animator. ! self.attachmentBehavior.anchorPoint = position; } else if (sender.state == UIGestureRecognizerStateEnded) {
  24. Pan Gesture Selector - Part 2 ! } else if

    (sender.state == UIGestureRecognizerStateEnded) { [self.animator removeBehavior:self.attachmentBehavior]; CGPoint velocity = [sender velocityInView:self]; if (fabsf(velocity.x) > 500 || fabsf(velocity.y) > 500) { UIPushBehavior *pushBehavior = [[UIPushBehavior alloc] initWithItems:@[self.imageView] mode:UIPushBehaviorModeInstantaneous]; [pushBehavior setTargetOffsetFromCenter:self.imageOffset forItem:self.imageView]; ! pushBehavior.pushDirection = CGVectorMake(velocity.x, velocity.y); pushBehavior.magnitude = MAX(fabsf(velocity.x), fabsf(velocity.y))/1.8; ! [self.animator addBehavior:pushBehavior]; UIDynamicItemBehavior *itemBehavior = [[UIDynamicItemBehavior alloc] initWithItems:@[self.imageView]]; __weak typeof(self) selfish = self; itemBehavior.action = ^{ if (!CGRectIntersectsRect(selfish.imageView.frame, selfish.bounds)) { [selfish.animator removeAllBehaviors]; [selfish animateBackToStartWithDuration:1.0]; }; }; [self.animator addBehavior:itemBehavior]; } else { [self animateBackToStartWithDuration:0.25]; } } }
  25. Pan Gesture Selector - Part 3 - (void)animateBackToStartWithDuration:(CGFloat)duration { //

    It's important that the animator behavoirs are inactive or // removed by this point to avoid problems with Core Animation [UIView animateWithDuration:duration animations:^{ self.imageView.center = self.oldCenter; self.imageView.transform = CGAffineTransformIdentity; }]; }
  26. UIKit Dynamics Further Reading UIDynamic Class Headers ! UIKit Dynamics

    Catalog Sample app. ! https://developer.apple.com/library/ios/samplecode/ DynamicsCatalog ! Double Encore Insights page ! http://www.doubleencore.com/insights/
  27. UIKit Dynamics Further Viewing WWDC videos: ! Getting Started with

    UIKit Dynamics ! Advanced Techniques with UIKit Dynamics ! Exploring Scroll Views on iOS 7