Hackatron - UIKit Dynamics
Upcoming SlideShare
Loading in...5
×
 

Hackatron - UIKit Dynamics

on

  • 374 views

 

Statistics

Views

Total Views
374
Views on SlideShare
371
Embed Views
3

Actions

Likes
1
Downloads
4
Comments
0

1 Embed 3

http://www.linkedin.com 3

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Hackatron - UIKit Dynamics Hackatron - UIKit Dynamics Presentation Transcript

  • UIKit Dynamics Let the physics flow Renzo G. Pretto iOS Developer
  • Who’s talking
  • Who’s talking
  • About me Renzo iOS Developer H-art ! #pragma mark founder renzo.pretto@pragmamark.org ! @rgpretto
  • Chi siamo programmatori e imprenditori, ma soprattutto appassionati
  • Cosa creare una community di sviluppatori iOS e OS X
  • Perché sentivamo l’esigenza di condividere e confrontarci
  • Dove nel mondo virtuale, ma soprattutto nel mondo reale
  • Come attraverso incontri periodici, eventi formativi e conferenze
  • Associazione dal Settembre siamo ufficialmente un’associazione culturale
  • Associazione dal Settembre siamo ufficialmente un’associazione culturale Marco Paolo Matteo Renzo Francesco Massimo Stefano Giuseppe
  • Statuto
  • Statuto  L’associazione senza fini di lucro #pragma mark ha lo scopo di svolgere attività di “community of practice, ovvero di condivisione delle conoscenze ed esperienze tra persone la cui professionalità ruota intorno le tecnologie informatiche e iOS in particolare, fornendo un nuovo modello per connetterle nello spirito dell’apprendimento, della conoscenza condivisa e della collaborazione sia come individui sia come gruppi”
  • 152 partecipanti 16 speaker 15 sponsor 8 organizzatori
  • 16 sessioni tecniche 10 ore di conferenza 2 track tematiche 20 gadget, licenze e coupon
  • Comunità
  • Ottobre 2013 la comunità è cresciuta molto, oggi siamo in 150
  • Partecipanti più di 300 persone hanno seguito i nostri eventi
  • Social 205 iscritti al gruppo su facebook e 122 follower su twitter
  • Eventi svolti 9 eventi
  • Dove Brescia, Bergamo,Verona,Venezia, Milano 
 e presto a Treviso e Roma
  • follow us @pragmamarkorg join to fb.com/groups/pragmamark/ subscribe on pragmamark.org
  • Today Agenda • Introduction and core concepts
  • Today Agenda • Introduction and core concepts • Standard effects: dynamic behaviors
  • Today Agenda • Introduction and core concepts • Standard effects: dynamic behaviors • Custom effects: custom behaviors
  • Today Agenda • Introduction and core concepts • Standard effects: dynamic behaviors • Custom effects: custom behaviors • Advanced concepts
  • Today Agenda • Introduction and core concepts • Standard effects: dynamic behaviors • Custom effects: custom behaviors • Advanced concepts • UIDynamicItem
  • Today Agenda • Introduction and core concepts • Standard effects: dynamic behaviors • Custom effects: custom behaviors • Advanced concepts • UIDynamicItem • Collection View
  • Today Agenda • Introduction and core concepts • Standard effects: dynamic behaviors • Custom effects: custom behaviors • Advanced concepts • UIDynamicItem • Collection View • Conclusion
  • UIKit Dynamics
  • UIKit Dynamics
  • UIKit Dynamics
  • Architecture UIDynamicAnimator
  • Architecture UIDynamicAnimator UIDynamicBehavior UIDynamicBehavior UIDynamicBehavior
  • Architecture UIDynamicAnimator UIDynamicBehavior UIDynamicBehavior UIDynamicBehavior
  • Architecture UIDynamicAnimator UIDynamicBehavior View UIDynamicBehavior UIDynamicBehavior
  • Architecture UIDynamicAnimator UIDynamicBehavior UIDynamicBehavior View View UIDynamicBehavior
  • Architecture UIDynamicAnimator UIDynamicBehavior UIDynamicBehavior UIDynamicBehavior View View View
  • Architecture UIDynamicAnimator Reference view UIDynamicBehavior UIDynamicBehavior UIDynamicBehavior View View View
  • Architecture UIDynamicAnimator Reference view UIDynamicBehavior UIDynamicBehavior UIDynamicBehavior View View View
  • UIDynamicAnimator UIDynamicAnimator
  • UIDynamicAnimator • Define the coordinate system UIDynamicAnimator Reference view
  • UIDynamicAnimator • Define the coordinate system • Wraps underline engine UIDynamicAnimator Reference view
  • UIDynamicAnimator • Define the coordinate system • Wraps underline engine • Keeps track of all the associated behaviors UIDynamicAnimator Reference view
  • UIDynamicAnimator • Define the coordinate system • Wraps underline engine • Keeps track of all the associated behaviors • Run and optimize the animation UIDynamicAnimator Reference view
  • UIDynamicAnimator • Define the coordinate system UIDynamicAnimator • Wraps underline engine • Keeps track of all the associated behaviors Reference view • Run and optimize the animation • Each dynamic animator is independent from other dynamic animators
  • UIDynamicAnimator • Define the coordinate system UIDynamicAnimator • Wraps underline engine • Keeps track of all the associated behaviors Reference view • Run and optimize the animation • Each dynamic animator is independent from other dynamic animators UIDynamicAnimator *dynamicAnimator; ! dynamicAnimator = [[UIDynamicAnimator alloc] initWithReferenceView:referenceView]; ! dynamicAnimator.delegate = self; ... ! [dynamicAnimator addBehavior:firstBehavior]; [dynamicAnimator addBehavior:secondBehavior]; ...
  • UIDynamicAnimator • Define the coordinate system UIDynamicAnimator • Wraps underline engine • Keeps track of all the associated behaviors Reference view • Run and optimize the animation • Each dynamic animator is independent from other dynamic animators UIDynamicAnimator *dynamicAnimator; ! dynamicAnimator = [[UIDynamicAnimator alloc] initWithReferenceView:referenceView]; ! dynamicAnimator.delegate = self; ... ! [dynamicAnimator addBehavior:firstBehavior]; [dynamicAnimator addBehavior:secondBehavior]; ...
  • UIDynamicAnimator • Define the coordinate system UIDynamicAnimator • Wraps underline engine • Keeps track of all the associated behaviors Reference view • Run and optimize the animation • Each dynamic animator is independent from other dynamic animators UIDynamicAnimator *dynamicAnimator; ! dynamicAnimator = [[UIDynamicAnimator alloc] initWithReferenceView:referenceView]; ! dynamicAnimator.delegate = self; ... ! [dynamicAnimator addBehavior:firstBehavior]; [dynamicAnimator addBehavior:secondBehavior]; ...
  • UIDynamicAnimator • Define the coordinate system UIDynamicAnimator • Wraps underline engine • Keeps track of all the associated behaviors Reference view • Run and optimize the animation • Each dynamic animator is independent from other dynamic animators UIDynamicAnimator *dynamicAnimator; ! dynamicAnimator = [[UIDynamicAnimator alloc] initWithReferenceView:referenceView]; ! dynamicAnimator.delegate = self; ... ! [dynamicAnimator addBehavior:firstBehavior]; [dynamicAnimator addBehavior:secondBehavior]; ...
  • UIDynamicAnimatorDelegate @protocol UIDynamicAnimatorDelegate <NSObject> ! @optional - (void)dynamicAnimatorWillResume:(UIDynamicAnimator*)animator; - (void)dynamicAnimatorDidPause:(UIDynamicAnimator*)animator; ! @end
  • UIDynamicAnimatorDelegate @protocol UIDynamicAnimatorDelegate <NSObject> ! @optional - (void)dynamicAnimatorWillResume:(UIDynamicAnimator*)animator; - (void)dynamicAnimatorDidPause:(UIDynamicAnimator*)animator; ! @end • Notify pausing and resuming of UIKit Dynamic animator
  • UIDynamicBehaviour UIDynamicBehavior
  • UIDynamicBehaviour UIDynamicAnimator UIDynamicBehavior • Associated to UIDynamicAnimator
  • UIDynamicBehaviour UIDynamicAnimator UIDynamicBehavior • Associated to UIDynamicAnimator • Add and remove behaviours to an animator at any times
  • UIDynamicBehaviour UIDynamicAnimator UIDynamicBehavior View View • Associated to UIDynamicAnimator • Add and remove behaviours to an animator at any times • Usually associated to a view or a set of view
  • UIDynamicBehaviour UIDynamicAnimator UIDynamicBehavior View View UIDynamicBehavior View • Associated to UIDynamicAnimator • Add and remove behaviours to an animator at any times • Usually associated to a view or a set of view • Composed
  • UIDynamicBehaviour UIDynamicAnimator UIDynamicBehavior View View UIDynamicBehavior View • Associated to UIDynamicAnimator • Add and remove behaviours to an animator at any times • Usually associated to a view or a set of view • Composed • Can be subclassed
  • Behaviors Common characteristics • Initialised with items to animate
  • Behaviors Common characteristics • Initialised with items to animate • Items can be added to behavior at any times
  • Behaviors Common characteristics • Initialised with items to animate • Items can be added to behavior at any times • Behaviour can be configured before or after add to an animator
  • Behaviors Common characteristics • Initialised with items to animate • Items can be added to behavior at any times • Behaviour can be configured before or after add to an animator • Behavior influence stops when behaviour is removed
  • Primitive behaviors
  • Default Behaviors UIDynamicBehavior
  • Default Behaviors UIDynamicBehavior • Gravity UIGravityBehavior
  • Default Behaviors UIDynamicBehavior • Gravity • Collisions UIGravityBehavior UICollisionBehavior
  • Default Behaviors UIDynamicBehavior • Gravity • Collisions • Attachments UIGravityBehavior UICollisionBehavior UIAttachmentBehavior
  • Default Behaviors UIDynamicBehavior • Gravity • Collisions • Attachments • Snap UIGravityBehavior UICollisionBehavior UIAttachmentBehavior UISnapBehavior
  • Default Behaviors UIDynamicBehavior • Gravity • Collisions • Attachments UIGravityBehavior UICollisionBehavior UIAttachmentBehavior • Snap UISnapBehavior • Forces UIPushBehavior
  • Default Behaviors UIDynamicBehavior • Gravity • Collisions • Attachments UIGravityBehavior UICollisionBehavior UIAttachmentBehavior • Snap UISnapBehavior • Forces UIPushBehavior • Item properties UIDynamicItemBehavior
  • UIGravityBehavior UIDynamicBehavior UIGravityBehavior UICollisionBehavior UIAttachmentBehavior UISnapBehavior UIPushBehavior UIDynamicItemBehavior
  • UIGravityBehavior UIDynamicBehavior UIGravityBehavior UICollisionBehavior UIAttachmentBehavior UISnapBehavior UIPushBehavior UIDynamicItemBehavior
  • UIGravityBehavior
  • UIGravityBehavior @interface DPGravityViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator *animator; @property (weak, nonatomic) IBOutlet UIView *greenView; @end @implementation DPGravityViewController ... - (void)viewDidLoad { [super viewDidLoad]; ! self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; NSArray *items = @[self.greenView]; ! ! UIGravityBehavior *gravityBehavior; gravityBehavior = [[UIGravityBehavior alloc] initWithItems:items]; [self.animator addBehavior:gravityBehavior]; } ... @end
  • UIGravityBehavior @interface DPGravityViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator *animator; @property (weak, nonatomic) IBOutlet UIView *greenView; @end @implementation DPGravityViewController ... - (void)viewDidLoad { [super viewDidLoad]; ! self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; NSArray *items = @[self.greenView]; ! ! UIGravityBehavior *gravityBehavior; gravityBehavior = [[UIGravityBehavior alloc] initWithItems:items]; [self.animator addBehavior:gravityBehavior]; } ... @end
  • UIGravityBehavior @interface DPGravityViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator *animator; @property (weak, nonatomic) IBOutlet UIView *greenView; @end @implementation DPGravityViewController ... - (void)viewDidLoad { [super viewDidLoad]; ! self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; NSArray *items = @[self.greenView]; ! ! UIGravityBehavior *gravityBehavior; gravityBehavior = [[UIGravityBehavior alloc] initWithItems:items]; [self.animator addBehavior:gravityBehavior]; } ... @end
  • UIGravityBehavior @interface DPGravityViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator *animator; @property (weak, nonatomic) IBOutlet UIView *greenView; @end @implementation DPGravityViewController ... - (void)viewDidLoad { [super viewDidLoad]; ! self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; NSArray *items = @[self.greenView]; ! ! UIGravityBehavior *gravityBehavior; gravityBehavior = [[UIGravityBehavior alloc] initWithItems:items]; [self.animator addBehavior:gravityBehavior]; } ... @end
  • UIGravityBehavior @interface DPGravityViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator *animator; @property (weak, nonatomic) IBOutlet UIView *greenView; @end @implementation DPGravityViewController ... - (void)viewDidLoad { [super viewDidLoad]; ! self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; NSArray *items = @[self.greenView]; ! ! UIGravityBehavior *gravityBehavior; gravityBehavior = [[UIGravityBehavior alloc] initWithItems:items]; [self.animator addBehavior:gravityBehavior]; } ... @end
  • UIGravityBehavior • Defined by a gravity vector @property (readwrite, nonatomic) CGVector gravityDirection;
  • UIGravityBehavior • Defined by a gravity vector @property (readwrite, nonatomic) CGVector gravityDirection; or @property (readwrite, nonatomic) CGFloat angle; @property (readwrite, nonatomic) CGFloat magnitude;
  • UIGravityBehavior • Defined by a gravity vector @property (readwrite, nonatomic) CGVector gravityDirection; or @property (readwrite, nonatomic) CGFloat angle; @property (readwrite, nonatomic) CGFloat magnitude; • Default vector is (0.0, 1.0) (0.0, 1.0)
  • UIGravityBehavior • Defined by a gravity vector @property (readwrite, nonatomic) CGVector gravityDirection; or @property (readwrite, nonatomic) CGFloat angle; @property (readwrite, nonatomic) CGFloat magnitude; • Default vector is (0.0, 1.0) Magnitude 1.0 accelerate view to 1000 points/s2 • (0.0, 1.0)
  • UIGravityBehavior • Defined by a gravity vector @property (readwrite, nonatomic) CGVector gravityDirection; or @property (readwrite, nonatomic) CGFloat angle; @property (readwrite, nonatomic) CGFloat magnitude; • Default vector is (0.0, 1.0) Magnitude 1.0 accelerate view to 1000 points/s2 • • Can add and remove items at any time - (void)addItem:(id <UIDynamicItem>)item; - (void)removeItem:(id <UIDynamicItem>)item; (0.0, 1.0)
  • UICollisionBehavior UIDynamicBehavior UIGravityBehavior UICollisionBehavior UIAttachmentBehavior UISnapBehavior UIPushBehavior UIDynamicItemBehavior
  • UICollisionBehavior
  • UICollisionBehavior @interface DPCollisionsViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator *animator; @property (weak, nonatomic) IBOutlet UIView *greenView; @end ! @implementation DPGravityCollisionViewController ... - (void)viewDidLoad { [super viewDidLoad]; ! self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; NSArray *items = @[self.greenView]; ! UICollisionBehavior *collisionBehavior; collisionBehavior = [[UICollisionBehavior alloc] initWithItems:items]; collisionBehavior.translatesReferenceBoundsIntoBoundary = YES; collisionBehavior.collisionDelegate = self; UIGravityBehavior *gravityBehavior; gravityBehavior =[[UIGravityBehavior alloc] initWithItems:items]; } ... @end [self.animator addBehavior:collisionBehavior]; [self.animator addBehavior:gravityBehavior];
  • UICollisionBehavior @interface DPCollisionsViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator *animator; @property (weak, nonatomic) IBOutlet UIView *greenView; @end ! @implementation DPGravityCollisionViewController ... - (void)viewDidLoad { [super viewDidLoad]; ! self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; NSArray *items = @[self.greenView]; ! UICollisionBehavior *collisionBehavior; collisionBehavior = [[UICollisionBehavior alloc] initWithItems:items]; collisionBehavior.translatesReferenceBoundsIntoBoundary = YES; collisionBehavior.collisionDelegate = self; UIGravityBehavior *gravityBehavior; gravityBehavior =[[UIGravityBehavior alloc] initWithItems:items]; } ... @end [self.animator addBehavior:collisionBehavior]; [self.animator addBehavior:gravityBehavior];
  • UICollisionBehavior @interface DPCollisionsViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator *animator; @property (weak, nonatomic) IBOutlet UIView *greenView; @end ! @implementation DPGravityCollisionViewController ... - (void)viewDidLoad { [super viewDidLoad]; ! self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; NSArray *items = @[self.greenView]; ! UICollisionBehavior *collisionBehavior; collisionBehavior = [[UICollisionBehavior alloc] initWithItems:items]; collisionBehavior.translatesReferenceBoundsIntoBoundary = YES; collisionBehavior.collisionDelegate = self; UIGravityBehavior *gravityBehavior; gravityBehavior =[[UIGravityBehavior alloc] initWithItems:items]; } ... @end [self.animator addBehavior:collisionBehavior]; [self.animator addBehavior:gravityBehavior];
  • UICollisionBehavior @interface DPCollisionsViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator *animator; @property (weak, nonatomic) IBOutlet UIView *greenView; @end ! @implementation DPGravityCollisionViewController ... - (void)viewDidLoad { [super viewDidLoad]; ! self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; NSArray *items = @[self.greenView]; ! UICollisionBehavior *collisionBehavior; collisionBehavior = [[UICollisionBehavior alloc] initWithItems:items]; collisionBehavior.translatesReferenceBoundsIntoBoundary = YES; collisionBehavior.collisionDelegate = self; UIGravityBehavior *gravityBehavior; gravityBehavior =[[UIGravityBehavior alloc] initWithItems:items]; } ... @end [self.animator addBehavior:collisionBehavior]; [self.animator addBehavior:gravityBehavior];
  • UICollisionBehavior @interface DPCollisionsViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator *animator; @property (weak, nonatomic) IBOutlet UIView *greenView; @end ! @implementation DPGravityCollisionViewController ... - (void)viewDidLoad { [super viewDidLoad]; ! self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; NSArray *items = @[self.greenView]; ! UICollisionBehavior *collisionBehavior; collisionBehavior = [[UICollisionBehavior alloc] initWithItems:items]; collisionBehavior.translatesReferenceBoundsIntoBoundary = YES; collisionBehavior.collisionDelegate = self; UIGravityBehavior *gravityBehavior; gravityBehavior =[[UIGravityBehavior alloc] initWithItems:items]; } ... @end [self.animator addBehavior:collisionBehavior]; [self.animator addBehavior:gravityBehavior];
  • UICollisionBehavior @interface DPCollisionsViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator *animator; @property (weak, nonatomic) IBOutlet UIView *greenView; @end ! @implementation DPGravityCollisionViewController ... - (void)viewDidLoad { [super viewDidLoad]; ! self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; NSArray *items = @[self.greenView]; ! UICollisionBehavior *collisionBehavior; collisionBehavior = [[UICollisionBehavior alloc] initWithItems:items]; collisionBehavior.translatesReferenceBoundsIntoBoundary = YES; collisionBehavior.collisionDelegate = self; UIGravityBehavior *gravityBehavior; gravityBehavior =[[UIGravityBehavior alloc] initWithItems:items]; } ... @end [self.animator addBehavior:collisionBehavior]; [self.animator addBehavior:gravityBehavior];
  • UICollisionBehavior @interface DPCollisionsViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator *animator; @property (weak, nonatomic) IBOutlet UIView *greenView; @end ! @implementation DPGravityCollisionViewController ... - (void)viewDidLoad { [super viewDidLoad]; ! self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; NSArray *items = @[self.greenView]; ! UICollisionBehavior *collisionBehavior; collisionBehavior = [[UICollisionBehavior alloc] initWithItems:items]; collisionBehavior.translatesReferenceBoundsIntoBoundary = YES; collisionBehavior.collisionDelegate = self; UIGravityBehavior *gravityBehavior; gravityBehavior =[[UIGravityBehavior alloc] initWithItems:items]; } ... @end [self.animator addBehavior:collisionBehavior]; [self.animator addBehavior:gravityBehavior];
  • Collision Boundaries • Can specify different boundaries
  • Collision Boundaries • Can specify different boundaries • Reference view @property (nonatomic, readwrite) BOOL translatesReferenceBoundsIntoBoundary;
  • Collision Boundaries • Can specify different boundaries • Reference view @property (nonatomic, readwrite) BOOL translatesReferenceBoundsIntoBoundary; • Insets to reference view - (void)setTranslatesReferenceBoundsIntoBoundaryWithInsets:(UIEdgeInsets)insets;
  • Collision Boundaries • Can specify different boundaries • Reference view @property (nonatomic, readwrite) BOOL translatesReferenceBoundsIntoBoundary; • Insets to reference view - (void)setTranslatesReferenceBoundsIntoBoundaryWithInsets:(UIEdgeInsets)insets; • Segmentes - (void)addBoundaryWithIdentifier:(id <NSCopying>)identifier fromPoint:(CGPoint)p1 toPoint:(CGPoint)p2;
  • Collision Boundaries • Can specify different boundaries • Reference view @property (nonatomic, readwrite) BOOL translatesReferenceBoundsIntoBoundary; • Insets to reference view - (void)setTranslatesReferenceBoundsIntoBoundaryWithInsets:(UIEdgeInsets)insets; • Segmentes - (void)addBoundaryWithIdentifier:(id <NSCopying>)identifier fromPoint:(CGPoint)p1 toPoint:(CGPoint)p2; • Bezier paths (approximated) - (void)addBoundaryWithIdentifier:(id <NSCopying>)identifier forPath:(UIBezierPath*)bezierPath;
  • Collision Boundaries • Can specify different boundaries • Reference view @property (nonatomic, readwrite) BOOL translatesReferenceBoundsIntoBoundary; • Insets to reference view - (void)setTranslatesReferenceBoundsIntoBoundaryWithInsets:(UIEdgeInsets)insets; • Segmentes - (void)addBoundaryWithIdentifier:(id <NSCopying>)identifier fromPoint:(CGPoint)p1 toPoint:(CGPoint)p2; • Bezier paths (approximated) - (void)addBoundaryWithIdentifier:(id <NSCopying>)identifier forPath:(UIBezierPath*)bezierPath;
  • Collision Boundaries • Can specify different boundaries • Reference view @property (nonatomic, readwrite) BOOL translatesReferenceBoundsIntoBoundary; • Insets to reference view - (void)setTranslatesReferenceBoundsIntoBoundaryWithInsets:(UIEdgeInsets)insets; • Segmentes - (void)addBoundaryWithIdentifier:(id <NSCopying>)identifier fromPoint:(CGPoint)p1 toPoint:(CGPoint)p2; • Bezier paths (approximated) - (void)addBoundaryWithIdentifier:(id <NSCopying>)identifier forPath:(UIBezierPath*)bezierPath; • Boundaries don't have an existence on screen
  • Collision Mode • Property collisionmode
  • Collision Mode • Property collisionmode @property (nonatomic, readwrite) UICollisionBehaviorMode collisionMode;
  • Collision Mode • Property collisionmode @property (nonatomic, readwrite) UICollisionBehaviorMode collisionMode; • UICollisionBehaviorModeBoundaries
  • Collision Mode • Property collisionmode @property (nonatomic, readwrite) UICollisionBehaviorMode collisionMode; • UICollisionBehaviorModeBoundaries • UICollisionBehaviorModeItems
  • Collision Mode • Property collisionmode @property (nonatomic, readwrite) UICollisionBehaviorMode collisionMode; • UICollisionBehaviorModeBoundaries • UICollisionBehaviorModeItems • UICollisionBehaviorModeEverything (default)
  • Tips • Can use multiple collision behaviors
  • Tips • Can use multiple collision behaviors • Add and remove items to this behaviour anytime - (void)addItem:(id <UIDynamicItem>)item; - (void)removeItem:(id <UIDynamicItem>)item;
  • Tips • Can use multiple collision behaviors • Add and remove items to this behaviour anytime - (void)addItem:(id <UIDynamicItem>)item; - (void)removeItem:(id <UIDynamicItem>)item; • Collision detection have CPU cost
  • UICollisionBehaviorDelegate • Methods that inform collision start / end between view
  • UICollisionBehaviorDelegate • Methods that inform collision start / end between view - (void)collisionBehavior:(UICollisionBehavior*)behavior beganContactForItem:(id <UIDynamicItem>)item1 withItem:(id <UIDynamicItem>)item2 atPoint:(CGPoint)p; - (void)collisionBehavior:(UICollisionBehavior*)behavior endedContactForItem:(id <UIDynamicItem>)item1 withItem:(id <UIDynamicItem>)item2;
  • UICollisionBehaviorDelegate • Methods that inform collision start / end between view - (void)collisionBehavior:(UICollisionBehavior*)behavior beganContactForItem:(id <UIDynamicItem>)item1 withItem:(id <UIDynamicItem>)item2 atPoint:(CGPoint)p; - (void)collisionBehavior:(UICollisionBehavior*)behavior endedContactForItem:(id <UIDynamicItem>)item1 withItem:(id <UIDynamicItem>)item2; • Methods that inform collision start /end between boundaries
  • UICollisionBehaviorDelegate • Methods that inform collision start / end between view - (void)collisionBehavior:(UICollisionBehavior*)behavior beganContactForItem:(id <UIDynamicItem>)item1 withItem:(id <UIDynamicItem>)item2 atPoint:(CGPoint)p; - (void)collisionBehavior:(UICollisionBehavior*)behavior endedContactForItem:(id <UIDynamicItem>)item1 withItem:(id <UIDynamicItem>)item2; • Methods that inform collision start /end between boundaries - (void)collisionBehavior:(UICollisionBehavior*)behavior beganContactForItem:(id <UIDynamicItem>)item withBoundaryIdentifier:(id <NSCopying>)identifier atPoint:(CGPoint)p; - (void)collisionBehavior:(UICollisionBehavior*)behavior endedContactForItem:(id <UIDynamicItem>)item withBoundaryIdentifier:(id <NSCopying>)identifier;
  • UICollisionBehaviorDelegate • Methods that inform collision start / end between view - (void)collisionBehavior:(UICollisionBehavior*)behavior beganContactForItem:(id <UIDynamicItem>)item1 withItem:(id <UIDynamicItem>)item2 atPoint:(CGPoint)p; - (void)collisionBehavior:(UICollisionBehavior*)behavior endedContactForItem:(id <UIDynamicItem>)item1 withItem:(id <UIDynamicItem>)item2; • Methods that inform collision start /end between boundaries - (void)collisionBehavior:(UICollisionBehavior*)behavior beganContactForItem:(id <UIDynamicItem>)item withBoundaryIdentifier:(id <NSCopying>)identifier atPoint:(CGPoint)p; - (void)collisionBehavior:(UICollisionBehavior*)behavior endedContactForItem:(id <UIDynamicItem>)item withBoundaryIdentifier:(id <NSCopying>)identifier;
  • UICollisionBehaviorDelegate • Methods that inform collision start / end between view - (void)collisionBehavior:(UICollisionBehavior*)behavior beganContactForItem:(id <UIDynamicItem>)item1 withItem:(id <UIDynamicItem>)item2 atPoint:(CGPoint)p; - (void)collisionBehavior:(UICollisionBehavior*)behavior endedContactForItem:(id <UIDynamicItem>)item1 withItem:(id <UIDynamicItem>)item2; • Methods that inform collision start /end between boundaries - (void)collisionBehavior:(UICollisionBehavior*)behavior beganContactForItem:(id <UIDynamicItem>)item withBoundaryIdentifier:(id <NSCopying>)identifier atPoint:(CGPoint)p; - (void)collisionBehavior:(UICollisionBehavior*)behavior endedContactForItem:(id <UIDynamicItem>)item withBoundaryIdentifier:(id <NSCopying>)identifier; ! • Reference view has nil identifier
  • UIAttachmentBehavior UIDynamicBehavior UIGravityBehavior UICollisionBehavior UIAttachmentBehavior UISnapBehavior UIPushBehavior UIDynamicItemBehavior
  • UIAttachmentBehavior
  • UIAttachmentBehavior @interface DPAttachmentViewController : UIViewController @property (weak, nonatomic) IBOutlet UIView *redView; @property (weak, nonatomic) IBOutlet UIView *greenView; @property (strong, nonatomic) UIDynamicAnimator *animator; @end ! @implementation DPAttachmentViewController ... - (void)viewDidLoad { [super viewDidLoad]; ! self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; UIAttachmentBehavior *attachmentBehavior; attachmentBehavior =[[UIAttachmentBehavior alloc] initWithItem:self.greenView attachedToItem:self.redView]; [self.animator addBehavior:attachmentBehavior]; } ! - (IBAction)handlePanGesture:(UIPanGestureRecognizer *)gestureRecognizer { ! CGPoint anchorPoint = [gestureRecognizer locationInView:self.view]; self.redView.center = anchorPoint; [self.animator updateItemUsingCurrentState:self.redView]; } ... @end
  • UIAttachmentBehavior @interface DPAttachmentViewController : UIViewController @property (weak, nonatomic) IBOutlet UIView *redView; @property (weak, nonatomic) IBOutlet UIView *greenView; @property (strong, nonatomic) UIDynamicAnimator *animator; @end ! @implementation DPAttachmentViewController ... - (void)viewDidLoad { [super viewDidLoad]; ! self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; UIAttachmentBehavior *attachmentBehavior; attachmentBehavior =[[UIAttachmentBehavior alloc] initWithItem:self.greenView attachedToItem:self.redView]; [self.animator addBehavior:attachmentBehavior]; } ! - (IBAction)handlePanGesture:(UIPanGestureRecognizer *)gestureRecognizer { ! CGPoint anchorPoint = [gestureRecognizer locationInView:self.view]; self.redView.center = anchorPoint; [self.animator updateItemUsingCurrentState:self.redView]; } ... @end
  • UIAttachmentBehavior @interface DPAttachmentViewController : UIViewController @property (weak, nonatomic) IBOutlet UIView *redView; @property (weak, nonatomic) IBOutlet UIView *greenView; @property (strong, nonatomic) UIDynamicAnimator *animator; @end ! @implementation DPAttachmentViewController ... - (void)viewDidLoad { [super viewDidLoad]; ! self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; UIAttachmentBehavior *attachmentBehavior; attachmentBehavior =[[UIAttachmentBehavior alloc] initWithItem:self.greenView attachedToItem:self.redView]; [self.animator addBehavior:attachmentBehavior]; } ! - (IBAction)handlePanGesture:(UIPanGestureRecognizer *)gestureRecognizer { ! CGPoint anchorPoint = [gestureRecognizer locationInView:self.view]; self.redView.center = anchorPoint; [self.animator updateItemUsingCurrentState:self.redView]; } ... @end
  • UIAttachmentBehavior @interface DPAttachmentViewController : UIViewController @property (weak, nonatomic) IBOutlet UIView *redView; @property (weak, nonatomic) IBOutlet UIView *greenView; @property (strong, nonatomic) UIDynamicAnimator *animator; @end ! @implementation DPAttachmentViewController ... - (void)viewDidLoad { [super viewDidLoad]; ! self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; UIAttachmentBehavior *attachmentBehavior; attachmentBehavior =[[UIAttachmentBehavior alloc] initWithItem:self.greenView attachedToItem:self.redView]; [self.animator addBehavior:attachmentBehavior]; } ! - (IBAction)handlePanGesture:(UIPanGestureRecognizer *)gestureRecognizer { ! CGPoint anchorPoint = [gestureRecognizer locationInView:self.view]; self.redView.center = anchorPoint; [self.animator updateItemUsingCurrentState:self.redView]; } ... @end
  • UIAttachmentBehavior @interface DPAttachmentViewController : UIViewController @property (weak, nonatomic) IBOutlet UIView *redView; @property (weak, nonatomic) IBOutlet UIView *greenView; @property (strong, nonatomic) UIDynamicAnimator *animator; @end ! @implementation DPAttachmentViewController ... - (void)viewDidLoad { [super viewDidLoad]; ! self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; UIAttachmentBehavior *attachmentBehavior; attachmentBehavior =[[UIAttachmentBehavior alloc] initWithItem:self.greenView attachedToItem:self.redView]; [self.animator addBehavior:attachmentBehavior]; } ! - (IBAction)handlePanGesture:(UIPanGestureRecognizer *)gestureRecognizer { ! CGPoint anchorPoint = [gestureRecognizer locationInView:self.view]; self.redView.center = anchorPoint; [self.animator updateItemUsingCurrentState:self.redView]; } ... @end
  • UIAttachmentBehavior @interface DPAttachmentViewController : UIViewController @property (weak, nonatomic) IBOutlet UIView *redView; @property (weak, nonatomic) IBOutlet UIView *greenView; @property (strong, nonatomic) UIDynamicAnimator *animator; @end ! @implementation DPAttachmentViewController ... - (void)viewDidLoad { [super viewDidLoad]; ! self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; UIAttachmentBehavior *attachmentBehavior; attachmentBehavior =[[UIAttachmentBehavior alloc] initWithItem:self.greenView attachedToItem:self.redView]; [self.animator addBehavior:attachmentBehavior]; } ! - (IBAction)handlePanGesture:(UIPanGestureRecognizer *)gestureRecognizer { ! CGPoint anchorPoint = [gestureRecognizer locationInView:self.view]; self.redView.center = anchorPoint; [self.animator updateItemUsingCurrentState:self.redView]; } ... @end
  • UIAttachmentBehavior • View connected to an attachment point
  • UIAttachmentBehavior • View connected to an attachment point - (instancetype)initWithItem:(id <UIDynamicItem>)item attachedToAnchor:(CGPoint)point;
  • UIAttachmentBehavior • View connected to an attachment point - (instancetype)initWithItem:(id <UIDynamicItem>)item attachedToAnchor:(CGPoint)point; • Two views connected together
  • UIAttachmentBehavior • View connected to an attachment point - (instancetype)initWithItem:(id <UIDynamicItem>)item attachedToAnchor:(CGPoint)point; • Two views connected together - (instancetype)initWithItem:(id <UIDynamicItem>)item1 attachedToItem:(id <UIDynamicItem>)item2;
  • UIAttachmentBehavior • View connected to an attachment point - (instancetype)initWithItem:(id <UIDynamicItem>)item attachedToAnchor:(CGPoint)point; • Two views connected together - (instancetype)initWithItem:(id <UIDynamicItem>)item1 attachedToItem:(id <UIDynamicItem>)item2; • Specify connection point offset
  • UIAttachmentBehavior • View connected to an attachment point - (instancetype)initWithItem:(id <UIDynamicItem>)item attachedToAnchor:(CGPoint)point; • Two views connected together - (instancetype)initWithItem:(id <UIDynamicItem>)item1 attachedToItem:(id <UIDynamicItem>)item2; • Specify connection point offset - (instancetype)initWithItem:(id <UIDynamicItem>)item offsetFromCenter:(UIOffset)offset attachedToAnchor:(CGPoint)point;
  • UIAttachmentBehavior • View connected to an attachment point - (instancetype)initWithItem:(id <UIDynamicItem>)item attachedToAnchor:(CGPoint)point; • Two views connected together - (instancetype)initWithItem:(id <UIDynamicItem>)item1 attachedToItem:(id <UIDynamicItem>)item2; • Specify connection point offset - (instancetype)initWithItem:(id <UIDynamicItem>)item offsetFromCenter:(UIOffset)offset attachedToAnchor:(CGPoint)point; - (instancetype)initWithItem:(id <UIDynamicItem>)item1 offsetFromCenter:(UIOffset)offset1 attachedToItem:(id <UIDynamicItem>)item2 offsetFromCenter:(UIOffset)offset2;
  • Springs • Springs
  • Springs • Springs @property (readwrite, nonatomic) CGFloat damping;
  • Springs • Springs @property (readwrite, nonatomic) CGFloat damping; @property (readwrite, nonatomic) CGFloat frequency;
  • Springs • Springs @property (readwrite, nonatomic) CGFloat damping; @property (readwrite, nonatomic) CGFloat frequency;
  • UISnapBehavior UIDynamicBehavior UIGravityBehavior UICollisionBehavior UIAttachmentBehavior UISnapBehavior UIPushBehavior UIDynamicItemBehavior
  • UISnapBehavior
  • UISnapBehavior interface DPSnapViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator *animator; @property (weak, nonatomic) IBOutlet UIView *greenView; @end ! @implementation DPSnapViewController ... - (void)viewDidLoad { [super viewDidLoad]; ! } self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; ! - (IBAction)handleTapGesture:(UITapGestureRecognizer *)gestureRecognizer { ! CGPoint snapPoint = [gestureRecognizer locationInView:self.view]; if (nil != self.snapBehavior) { [self.dynamicAnimator removeBehavior:self.snapBehavior]; } self.snapBehavior = [[UISnapBehavior alloc] initWithItem:self.greenView snapToPoint:snapPoint]; [self.animator addBehavior:self.snapBehavior]; } ... @end
  • UISnapBehavior interface DPSnapViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator *animator; @property (weak, nonatomic) IBOutlet UIView *greenView; @end ! @implementation DPSnapViewController ... - (void)viewDidLoad { [super viewDidLoad]; ! } self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; ! - (IBAction)handleTapGesture:(UITapGestureRecognizer *)gestureRecognizer { ! CGPoint snapPoint = [gestureRecognizer locationInView:self.view]; if (nil != self.snapBehavior) { [self.dynamicAnimator removeBehavior:self.snapBehavior]; } self.snapBehavior = [[UISnapBehavior alloc] initWithItem:self.greenView snapToPoint:snapPoint]; [self.animator addBehavior:self.snapBehavior]; } ... @end
  • UISnapBehavior interface DPSnapViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator *animator; @property (weak, nonatomic) IBOutlet UIView *greenView; @end ! @implementation DPSnapViewController ... - (void)viewDidLoad { [super viewDidLoad]; ! } self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; ! - (IBAction)handleTapGesture:(UITapGestureRecognizer *)gestureRecognizer { ! CGPoint snapPoint = [gestureRecognizer locationInView:self.view]; if (nil != self.snapBehavior) { [self.dynamicAnimator removeBehavior:self.snapBehavior]; } self.snapBehavior = [[UISnapBehavior alloc] initWithItem:self.greenView snapToPoint:snapPoint]; [self.animator addBehavior:self.snapBehavior]; } ... @end
  • UISnapBehavior interface DPSnapViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator *animator; @property (weak, nonatomic) IBOutlet UIView *greenView; @end ! @implementation DPSnapViewController ... - (void)viewDidLoad { [super viewDidLoad]; ! } self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; ! - (IBAction)handleTapGesture:(UITapGestureRecognizer *)gestureRecognizer { ! CGPoint snapPoint = [gestureRecognizer locationInView:self.view]; if (nil != self.snapBehavior) { [self.dynamicAnimator removeBehavior:self.snapBehavior]; } self.snapBehavior = [[UISnapBehavior alloc] initWithItem:self.greenView snapToPoint:snapPoint]; [self.animator addBehavior:self.snapBehavior]; } ... @end
  • UISnapBehavior interface DPSnapViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator *animator; @property (weak, nonatomic) IBOutlet UIView *greenView; @end ! @implementation DPSnapViewController ... - (void)viewDidLoad { [super viewDidLoad]; ! } self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; ! - (IBAction)handleTapGesture:(UITapGestureRecognizer *)gestureRecognizer { ! CGPoint snapPoint = [gestureRecognizer locationInView:self.view]; if (nil != self.snapBehavior) { [self.dynamicAnimator removeBehavior:self.snapBehavior]; } self.snapBehavior = [[UISnapBehavior alloc] initWithItem:self.greenView snapToPoint:snapPoint]; [self.animator addBehavior:self.snapBehavior]; } ... @end
  • UISnapBehavior interface DPSnapViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator *animator; @property (weak, nonatomic) IBOutlet UIView *greenView; @end ! @implementation DPSnapViewController ... - (void)viewDidLoad { [super viewDidLoad]; ! } self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; ! - (IBAction)handleTapGesture:(UITapGestureRecognizer *)gestureRecognizer { ! CGPoint snapPoint = [gestureRecognizer locationInView:self.view]; if (nil != self.snapBehavior) { [self.dynamicAnimator removeBehavior:self.snapBehavior]; } self.snapBehavior = [[UISnapBehavior alloc] initWithItem:self.greenView snapToPoint:snapPoint]; [self.animator addBehavior:self.snapBehavior]; } ... @end
  • UISnapBehavior • Snap view in place in non rotated state
  • UISnapBehavior • Snap view in place in non rotated state - (instancetype)initWithItem:(id <UIDynamicItem>)item snapToPoint:(CGPoint)point;
  • UISnapBehavior • Snap view in place in non rotated state - (instancetype)initWithItem:(id <UIDynamicItem>)item snapToPoint:(CGPoint)point; • Customize the dumping effects
  • UISnapBehavior • Snap view in place in non rotated state - (instancetype)initWithItem:(id <UIDynamicItem>)item snapToPoint:(CGPoint)point; • Customize the dumping effects @property (nonatomic, assign) CGFloat damping;
  • UIPushBehavior UIDynamicBehavior UIGravityBehavior UICollisionBehavior UIAttachmentBehavior UISnapBehavior UIPushBehavior UIDynamicItemBehavior
  • UIPushBehavior ~ =m~ F a
  • UIPushBehavior ~ F = m ~ , apply force to views: a •
  • UIPushBehavior ~ F = m ~ , apply force to views: a • - (instancetype)initWithItems:(NSArray *)items mode:(UIPushBehaviorMode)mode;
  • UIPushBehavior ~ F = m ~ , apply force to views: a • - (instancetype)initWithItems:(NSArray *)items mode:(UIPushBehaviorMode)mode; • Force vector expressed in two way:
  • UIPushBehavior ~ F = m ~ , apply force to views: a • - (instancetype)initWithItems:(NSArray *)items mode:(UIPushBehaviorMode)mode; • Force vector expressed in two way: @property (readwrite, nonatomic) CGVector pushDirection;
  • UIPushBehavior ~ F = m ~ , apply force to views: a • - (instancetype)initWithItems:(NSArray *)items mode:(UIPushBehaviorMode)mode; • Force vector expressed in two way: @property (readwrite, nonatomic) CGVector pushDirection; or @property (readwrite, nonatomic) CGFloat angle; @property (readwrite, nonatomic) CGFloat magnitude;
  • UIPushBehavior
  • UIPushBehavior • Customize where apply this force in the view
  • UIPushBehavior • Customize where apply this force in the view
  • UIPushBehavior • Customize where apply this force in the view - (void)setTargetOffsetFromCenter:(UIOffset)o forItem:(id <UIDynamicItem>)item;
  • UIPushBehavior • Customize where apply this force in the view - (void)setTargetOffsetFromCenter:(UIOffset)o forItem:(id <UIDynamicItem>)item;
  • UIPushBehavior • Customize where apply this force in the view - (void)setTargetOffsetFromCenter:(UIOffset)o forItem:(id <UIDynamicItem>)item; • Can add and remove items at any time
  • UIPushBehavior • Customize where apply this force in the view - (void)setTargetOffsetFromCenter:(UIOffset)o forItem:(id <UIDynamicItem>)item; • Can add and remove items at any time - (void)addItem:(id <UIDynamicItem>)item; - (void)removeItem:(id <UIDynamicItem>)item;
  • UIPushBehavior • Customize where apply this force in the view - (void)setTargetOffsetFromCenter:(UIOffset)o forItem:(id <UIDynamicItem>)item; • Can add and remove items at any time - (void)addItem:(id <UIDynamicItem>)item; - (void)removeItem:(id <UIDynamicItem>)item;
  • UIPushBehavior • Customize where apply this force in the view - (void)setTargetOffsetFromCenter:(UIOffset)o forItem:(id <UIDynamicItem>)item; • Can add and remove items at any time - (void)addItem:(id <UIDynamicItem>)item; - (void)removeItem:(id <UIDynamicItem>)item;
  • UIPushBehavior Mode • Different mode to apply forces: - (instancetype)initWithItems:(NSArray *)items mode:(UIPushBehaviorMode)mode;
  • UIPushBehavior Mode • Different mode to apply forces: - (instancetype)initWithItems:(NSArray *)items mode:(UIPushBehaviorMode)mode; • UIPushBehaviorModeContinuous
  • UIPushBehavior Mode • Different mode to apply forces: - (instancetype)initWithItems:(NSArray *)items mode:(UIPushBehaviorMode)mode; • UIPushBehaviorModeContinuous • force still be applied while behaviour is active
  • UIPushBehavior Mode • Different mode to apply forces: - (instancetype)initWithItems:(NSArray *)items mode:(UIPushBehaviorMode)mode; • UIPushBehaviorModeContinuous • force still be applied while behaviour is active • views accelerate
  • UIPushBehavior Mode • Different mode to apply forces: - (instancetype)initWithItems:(NSArray *)items mode:(UIPushBehaviorMode)mode; • UIPushBehaviorModeContinuous • force still be applied while behaviour is active • views accelerate •UIPushBehaviorModeInstantaneous
  • UIPushBehavior Mode • Different mode to apply forces: - (instancetype)initWithItems:(NSArray *)items mode:(UIPushBehaviorMode)mode; • UIPushBehaviorModeContinuous • force still be applied while behaviour is active • views accelerate •UIPushBehaviorModeInstantaneous • apply a very quick impulse
  • UIPushBehavior Mode • Different mode to apply forces: - (instancetype)initWithItems:(NSArray *)items mode:(UIPushBehaviorMode)mode; • UIPushBehaviorModeContinuous • force still be applied while behaviour is active • views accelerate •UIPushBehaviorModeInstantaneous • apply a very quick impulse • view immediately acquire velocity (no acceleration)
  • UIPushBehavior Mode • Different mode to apply forces: - (instancetype)initWithItems:(NSArray *)items mode:(UIPushBehaviorMode)mode; • UIPushBehaviorModeContinuous • force still be applied while behaviour is active • views accelerate •UIPushBehaviorModeInstantaneous • apply a very quick impulse • view immediately acquire velocity (no acceleration) • automatically disable itself after applying it
  • UIPushBehavior Mode • Different mode to apply forces: - (instancetype)initWithItems:(NSArray *)items mode:(UIPushBehaviorMode)mode; • UIPushBehaviorModeContinuous • force still be applied while behaviour is active • views accelerate •UIPushBehaviorModeInstantaneous • apply a very quick impulse • view immediately acquire velocity (no acceleration) • automatically disable itself after applying it • to re-enable: @property (nonatomic, readwrite) BOOL active;
  • Example: force comparison ~ F =m~ a ~ F ~= a m
  • Example: force comparison ~ F =m~ a ~ F ~= a m
  • Example: gravity comparison
  • Feel The Force!
  • Feel The Force! • Gravity
  • Feel The Force! • Gravity • views accelerate with the same rate
  • Feel The Force! • Gravity • views accelerate with the same rate • Push behavior in continuos mode
  • Feel The Force! • Gravity • views accelerate with the same rate • Push behavior in continuos mode • the smaller views accelerate more
  • Feel The Force! • Gravity • views accelerate with the same rate • Push behavior in continuos mode • the smaller views accelerate more • Push behavior in instantaneous mode
  • Feel The Force! • Gravity • views accelerate with the same rate • Push behavior in continuos mode • the smaller views accelerate more • Push behavior in instantaneous mode • view acquire velocity and then the velocity doesn’t change
  • Feel The Force! • Gravity • views accelerate with the same rate • Push behavior in continuos mode • the smaller views accelerate more • Push behavior in instantaneous mode • view acquire velocity and then the velocity doesn’t change • the smaller views acquire more velocity
  • Unit of Measure • Real world: Newton
  • Unit of Measure • Real world: Newton 1 Newton accelerate 1Kg at a rate of 1 m/s2 •
  • Unit of Measure • Real world: Newton 1 Newton accelerate 1Kg at a rate of 1 m/s2 • • UIKit: •  magnitude of 1.0 accelerate 100x100 point view to 100 points/s2
  • Unit of Measure • Real world: Newton 1 Newton accelerate 1Kg at a rate of 1 m/s2 • • UIKit: •  magnitude of 1.0 accelerate 100x100 point view to 100 points/s2 • “UIKit Newton”
  • UIDynamicItemBehavior UIDynamicBehavior UIGravityBehavior UICollisionBehavior UIAttachmentBehavior UISnapBehavior UIPushBehavior UIDynamicItemBehavior
  • UIDynamicItemBehavior • Customize dynamics properties for items
  • UIDynamicItemBehavior • Customize dynamics properties for items @property (readwrite, nonatomic) CGFloat elasticity;
  • UIDynamicItemBehavior • Customize dynamics properties for items @property (readwrite, nonatomic) CGFloat elasticity; @property (readwrite, nonatomic) CGFloat friction;
  • UIDynamicItemBehavior • Customize dynamics properties for items @property (readwrite, nonatomic) CGFloat elasticity; @property (readwrite, nonatomic) CGFloat friction; @property (readwrite, nonatomic) CGFloat density;
  • UIDynamicItemBehavior • Customize dynamics properties for items @property @property @property @property (readwrite, (readwrite, (readwrite, (readwrite, nonatomic) nonatomic) nonatomic) nonatomic) CGFloat CGFloat CGFloat CGFloat elasticity; friction; density; resistance;
  • UIDynamicItemBehavior • Customize dynamics properties for items @property @property @property @property @property (readwrite, (readwrite, (readwrite, (readwrite, (readwrite, nonatomic) nonatomic) nonatomic) nonatomic) nonatomic) CGFloat CGFloat CGFloat CGFloat CGFloat elasticity; friction; density; resistance; angularResistance;
  • UIDynamicItemBehavior • Customize dynamics properties for items @property @property @property @property @property @property (readwrite, (readwrite, (readwrite, (readwrite, (readwrite, (readwrite, nonatomic) nonatomic) nonatomic) nonatomic) nonatomic) nonatomic) CGFloat elasticity; CGFloat friction; CGFloat density; CGFloat resistance; CGFloat angularResistance; BOOL allowsRotation;
  • UIDynamicItemBehavior • Customize dynamics properties for items @property @property @property @property @property @property (readwrite, (readwrite, (readwrite, (readwrite, (readwrite, (readwrite, nonatomic) nonatomic) nonatomic) nonatomic) nonatomic) nonatomic) CGFloat elasticity; CGFloat friction; CGFloat density; CGFloat resistance; CGFloat angularResistance; BOOL allowsRotation; • Add linear velocity (points per second) - (void)addLinearVelocity:(CGPoint)velocity forItem:(id <UIDynamicItem>)item; - (CGPoint)linearVelocityForItem:(id <UIDynamicItem>)item;
  • UIDynamicItemBehavior • Customize dynamics properties for items @property @property @property @property @property @property (readwrite, (readwrite, (readwrite, (readwrite, (readwrite, (readwrite, nonatomic) nonatomic) nonatomic) nonatomic) nonatomic) nonatomic) CGFloat elasticity; CGFloat friction; CGFloat density; CGFloat resistance; CGFloat angularResistance; BOOL allowsRotation; • Add linear velocity (points per second) - (void)addLinearVelocity:(CGPoint)velocity forItem:(id <UIDynamicItem>)item; - (CGPoint)linearVelocityForItem:(id <UIDynamicItem>)item; • Add angular velocity (radians per second) - (void)addAngularVelocity:(CGFloat)velocity forItem:(id <UIDynamicItem>)item; - (CGFloat)angularVelocityForItem:(id <UIDynamicItem>)item;
  • UIDynamicItemBehavior • Customize dynamics properties for items @property @property @property @property @property @property (readwrite, (readwrite, (readwrite, (readwrite, (readwrite, (readwrite, nonatomic) nonatomic) nonatomic) nonatomic) nonatomic) nonatomic) CGFloat elasticity; CGFloat friction; CGFloat density; CGFloat resistance; CGFloat angularResistance; BOOL allowsRotation; • Add linear velocity (points per second) - (void)addLinearVelocity:(CGPoint)velocity forItem:(id <UIDynamicItem>)item; - (CGPoint)linearVelocityForItem:(id <UIDynamicItem>)item; • Add angular velocity (radians per second) - (void)addAngularVelocity:(CGFloat)velocity forItem:(id <UIDynamicItem>)item; - (CGFloat)angularVelocityForItem:(id <UIDynamicItem>)item; • Can add and remove items at any time
  • UIDynamicItemBehavior • Customize dynamics properties for items @property @property @property @property @property @property (readwrite, (readwrite, (readwrite, (readwrite, (readwrite, (readwrite, nonatomic) nonatomic) nonatomic) nonatomic) nonatomic) nonatomic) CGFloat elasticity; CGFloat friction; CGFloat density; CGFloat resistance; CGFloat angularResistance; BOOL allowsRotation; • Add linear velocity (points per second) - (void)addLinearVelocity:(CGPoint)velocity forItem:(id <UIDynamicItem>)item; - (CGPoint)linearVelocityForItem:(id <UIDynamicItem>)item; • Add angular velocity (radians per second) - (void)addAngularVelocity:(CGFloat)velocity forItem:(id <UIDynamicItem>)item; - (CGFloat)angularVelocityForItem:(id <UIDynamicItem>)item; • Can add and remove items at any time
  • UIDynamicItemBehavior • Customize dynamics properties for items @property @property @property @property @property @property (readwrite, (readwrite, (readwrite, (readwrite, (readwrite, (readwrite, nonatomic) nonatomic) nonatomic) nonatomic) nonatomic) nonatomic) CGFloat elasticity; CGFloat friction; CGFloat density; CGFloat resistance; CGFloat angularResistance; BOOL allowsRotation; • Add linear velocity (points per second) - (void)addLinearVelocity:(CGPoint)velocity forItem:(id <UIDynamicItem>)item; - (CGPoint)linearVelocityForItem:(id <UIDynamicItem>)item; • Add angular velocity (radians per second) - (void)addAngularVelocity:(CGFloat)velocity forItem:(id <UIDynamicItem>)item; - (CGFloat)angularVelocityForItem:(id <UIDynamicItem>)item; • Can add and remove items at any time
  • Long Story Short • Identify the type of dynamic items you want to animate
  • Long Story Short • Identify the type of dynamic items you want to animate • Define container or reference view
  • Long Story Short • Identify the type of dynamic items you want to animate • Define container or reference view • Create the behaviours
  • Long Story Short • Identify the type of dynamic items you want to animate • Define container or reference view • Create the behaviours • Add items to behaviours
  • Long Story Short • Identify the type of dynamic items you want to animate • Define container or reference view • Create the behaviours • Add items to behaviours • Configure, add or remove behaviors to an animator
  • Custom behaviors
  • Custom Behavior • Can subclass UIDynamicBehavior
  • Custom Behavior • Can subclass UIDynamicBehavior • add child behavior - (void)addChildBehavior:(UIDynamicBehavior *)behavior; - (void)removeChildBehavior:(UIDynamicBehavior *)behavior; @property (nonatomic, readonly, copy) NSArray* childBehaviors;
  • Custom Behavior • Can subclass UIDynamicBehavior • add child behavior - (void)addChildBehavior:(UIDynamicBehavior *)behavior; - (void)removeChildBehavior:(UIDynamicBehavior *)behavior; @property (nonatomic, readonly, copy) NSArray* childBehaviors; • No CPU cost or any runtime difference
  • Example: gravity & collision
  • Example: gravity & collision @interface DPGravityCollisionViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator * animator; @end ! ! @implementation DPGravityCollisionViewController ! - (void)viewDidLoad { [super viewDidLoad]; self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; self.animator.delegate = self; NSArray *items = @[...]; ! UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:items]; UICollisionBehavior *coll = [[UICollisionBehavior alloc] initWithItems:items]; coll.translatesReferenceBoundsIntoBoundary = YES; [self.animator addBehavior:gravity]; [self.animator addBehavior:coll]; } ! @end
  • Example: gravity & collision @interface DPGravityCollisionViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator * animator; @end ! ! @implementation DPGravityCollisionViewController ! - (void)viewDidLoad { [super viewDidLoad]; self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; self.animator.delegate = self; NSArray *items = @[...]; ! UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:items]; UICollisionBehavior *coll = [[UICollisionBehavior alloc] initWithItems:items]; coll.translatesReferenceBoundsIntoBoundary = YES; [self.animator addBehavior:gravity]; [self.animator addBehavior:coll]; } ! @end
  • Example: gravity & collision @interface DPGravityCollisionViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator * animator; @end ! ! @implementation DPGravityCollisionViewController ! - (void)viewDidLoad { [super viewDidLoad]; self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; self.animator.delegate = self; NSArray *items = @[...]; ! UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:items]; UICollisionBehavior *coll = [[UICollisionBehavior alloc] initWithItems:items]; coll.translatesReferenceBoundsIntoBoundary = YES; [self.animator addBehavior:gravity]; [self.animator addBehavior:coll]; } ! @end
  • Example: gravity & collision @interface DPGravityCollisionViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator * animator; @end ! ! @implementation DPGravityCollisionViewController ! - (void)viewDidLoad { [super viewDidLoad]; self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; self.animator.delegate = self; NSArray *items = @[...]; ! UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:items]; UICollisionBehavior *coll = [[UICollisionBehavior alloc] initWithItems:items]; coll.translatesReferenceBoundsIntoBoundary = YES; [self.animator addBehavior:gravity]; [self.animator addBehavior:coll]; } ! @end
  • Example: gravity & collision @interface DPGravityCollisionViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator * animator; @end ! ! @implementation DPGravityCollisionViewController ! - (void)viewDidLoad { [super viewDidLoad]; self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; self.animator.delegate = self; NSArray *items = @[...]; ! UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:items]; UICollisionBehavior *coll = [[UICollisionBehavior alloc] initWithItems:items]; coll.translatesReferenceBoundsIntoBoundary = YES; [self.animator addBehavior:gravity]; [self.animator addBehavior:coll]; } ! @end
  • Example: gravity & collision @interface DPGravityCollisionBehavior : UIDynamicBehavior - (instancetype)initWithItems:(NSArray *)items; @end ! ! @implementation DPGravityCollisionBehavior ! - (instancetype)initWithItems:(NSArray *)items { self = [super init]; ! ! } ! if (self) { UIGravityBehavior *gravity; UICollisionBehavior *collision; gravity =[[UIGravityBehavior alloc] initWithItems:items]; collision = [[UICollisionBehavior alloc] initWithItems:items]; collision.translatesReferenceBoundsIntoBoundary = YES; [self addChildBehavior:gravity]; [self addChildBehavior:collision]; } return self; @end
  • Example: gravity & collision @interface DPGravityCollisionBehavior : UIDynamicBehavior - (instancetype)initWithItems:(NSArray *)items; @end ! ! @implementation DPGravityCollisionBehavior ! - (instancetype)initWithItems:(NSArray *)items { self = [super init]; ! ! } ! if (self) { UIGravityBehavior *gravity; UICollisionBehavior *collision; gravity =[[UIGravityBehavior alloc] initWithItems:items]; collision = [[UICollisionBehavior alloc] initWithItems:items]; collision.translatesReferenceBoundsIntoBoundary = YES; [self addChildBehavior:gravity]; [self addChildBehavior:collision]; } return self; @end
  • Example: gravity & collision @interface DPGravityCollisionBehavior : UIDynamicBehavior - (instancetype)initWithItems:(NSArray *)items; @end ! ! @implementation DPGravityCollisionBehavior ! - (instancetype)initWithItems:(NSArray *)items { self = [super init]; ! ! } ! if (self) { UIGravityBehavior *gravity; UICollisionBehavior *collision; gravity =[[UIGravityBehavior alloc] initWithItems:items]; collision = [[UICollisionBehavior alloc] initWithItems:items]; collision.translatesReferenceBoundsIntoBoundary = YES; [self addChildBehavior:gravity]; [self addChildBehavior:collision]; } return self; @end
  • Example: gravity & collision @interface DPGravityCollisionBehavior : UIDynamicBehavior - (instancetype)initWithItems:(NSArray *)items; @end ! ! @implementation DPGravityCollisionBehavior ! - (instancetype)initWithItems:(NSArray *)items { self = [super init]; ! ! } ! if (self) { UIGravityBehavior *gravity; UICollisionBehavior *collision; gravity =[[UIGravityBehavior alloc] initWithItems:items]; collision = [[UICollisionBehavior alloc] initWithItems:items]; collision.translatesReferenceBoundsIntoBoundary = YES; [self addChildBehavior:gravity]; [self addChildBehavior:collision]; } return self; @end
  • Example: gravity & collision @interface DPGravityCollisionBehavior : UIDynamicBehavior - (instancetype)initWithItems:(NSArray *)items; @end ! ! @implementation DPGravityCollisionBehavior ! - (instancetype)initWithItems:(NSArray *)items { self = [super init]; ! ! } ! if (self) { UIGravityBehavior *gravity; UICollisionBehavior *collision; gravity =[[UIGravityBehavior alloc] initWithItems:items]; collision = [[UICollisionBehavior alloc] initWithItems:items]; collision.translatesReferenceBoundsIntoBoundary = YES; [self addChildBehavior:gravity]; [self addChildBehavior:collision]; } return self; @end
  • Example: gravity & collision @interface DPGravityCollisionBehavior : UIDynamicBehavior - (instancetype)initWithItems:(NSArray *)items; @end ! ! @implementation DPGravityCollisionBehavior ! - (instancetype)initWithItems:(NSArray *)items { self = [super init]; ! ! } ! if (self) { UIGravityBehavior *gravity; UICollisionBehavior *collision; gravity =[[UIGravityBehavior alloc] initWithItems:items]; collision = [[UICollisionBehavior alloc] initWithItems:items]; collision.translatesReferenceBoundsIntoBoundary = YES; [self addChildBehavior:gravity]; [self addChildBehavior:collision]; } return self; @end
  • Example: gravity & collision @interface DPGravityCollisionBehavior : UIDynamicBehavior - (instancetype)initWithItems:(NSArray *)items; @end ! ! @implementation DPGravityCollisionBehavior ! - (instancetype)initWithItems:(NSArray *)items { self = [super init]; ! ! } ! if (self) { UIGravityBehavior *gravity; UICollisionBehavior *collision; gravity =[[UIGravityBehavior alloc] initWithItems:items]; collision = [[UICollisionBehavior alloc] initWithItems:items]; collision.translatesReferenceBoundsIntoBoundary = YES; [self addChildBehavior:gravity]; [self addChildBehavior:collision]; } return self; @end
  • Example: gravity & collision @interface DPGravityCollisionBehavior : UIDynamicBehavior - (instancetype)initWithItems:(NSArray *)items; @end ! ! @implementation DPGravityCollisionBehavior ! - (instancetype)initWithItems:(NSArray *)items { self = [super init]; ! ! } ! if (self) { UIGravityBehavior *gravity; UICollisionBehavior *collision; gravity =[[UIGravityBehavior alloc] initWithItems:items]; collision = [[UICollisionBehavior alloc] initWithItems:items]; collision.translatesReferenceBoundsIntoBoundary = YES; [self addChildBehavior:gravity]; [self addChildBehavior:collision]; } return self; @end
  • Example: gravity & collision @interface DPGravityCollisionBehavior : UIDynamicBehavior - (instancetype)initWithItems:(NSArray *)items; @end ! ! @implementation DPGravityCollisionBehavior ! - (instancetype)initWithItems:(NSArray *)items { self = [super init]; ! ! } ! if (self) { UIGravityBehavior *gravity; UICollisionBehavior *collision; gravity =[[UIGravityBehavior alloc] initWithItems:items]; collision = [[UICollisionBehavior alloc] initWithItems:items]; collision.translatesReferenceBoundsIntoBoundary = YES; [self addChildBehavior:gravity]; [self addChildBehavior:collision]; } return self; @end
  • Example: gravity & collision @interface DPGravityCollisionViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator *animator; @end ! ! @implementation DPGravityCollisionViewController ! - (void)viewDidLoad { [super viewDidLoad]; self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; self.animator.delegate = self; ! ! ! ! ! !! ! NSArray *items = @[...]; UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:items]; UICollisionBehavior *coll = [[UICollisionBehavior alloc] initWithItems:items]; coll.translatesReferenceBoundsIntoBoundary = YES; [self.animator addBehavior:gravity]; [self.animator addBehavior:coll]; } ! @end
  • Example: gravity & collision @interface DPGravityCollisionViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator *animator; @end ! ! @implementation DPGravityCollisionViewController ! - (void)viewDidLoad { [super viewDidLoad]; self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; self.animator.delegate = self; ! ! ! ! ! ! ! NSArray *items = @[...]; DPGravityCollisionBehavior *gravityAndCollision; gravityAndCollision= [[DPGravityCollisionBehavior alloc] initWithItems:items]; [self.animator addBehavior:gravityAndCollision]; } ! @end
  • Action Block • Can define per-step actions
  • Action Block • Can define per-step actions @property (nonatomic, copy) void (^action)(void);
  • Action Block • Can define per-step actions @property (nonatomic, copy) void (^action)(void); • UIDynamicAnimator invoke this block in each simulation step
  • Action Block • Can define per-step actions @property (nonatomic, copy) void (^action)(void); • UIDynamicAnimator invoke this block in each simulation step • So performance are crucial
  • UIDynamicItem protocol
  • UIDynamicItem Protocol @protocol UIDynamicItem <NSObject> ! @property (nonatomic, readwrite) CGPoint center; @property (nonatomic, readonly) CGRect bounds; @property (nonatomic, readwrite) CGAffineTransform transform; ! @end
  • UIDynamicItem Protocol @protocol UIDynamicItem <NSObject> ! @property (nonatomic, readwrite) CGPoint center; @property (nonatomic, readonly) CGRect bounds; @property (nonatomic, readwrite) CGAffineTransform transform; ! @end • All items animated by UIKit Dynamics must implement this protocol
  • UIDynamicItem Protocol @protocol UIDynamicItem <NSObject> ! @property (nonatomic, readwrite) CGPoint center; @property (nonatomic, readonly) CGRect bounds; @property (nonatomic, readwrite) CGAffineTransform transform; ! @end • All items animated by UIKit Dynamics must implement this protocol • Describe what UIKit Dynamics needs to animate an item
  • UIDynamicItem Protocol @protocol UIDynamicItem <NSObject> ! @property (nonatomic, readwrite) CGPoint center; @property (nonatomic, readonly) CGRect bounds; @property (nonatomic, readwrite) CGAffineTransform transform; ! @end • All items animated by UIKit Dynamics must implement this protocol • Describe what UIKit Dynamics needs to animate an item • position: center
  • UIDynamicItem Protocol @protocol UIDynamicItem <NSObject> ! @property (nonatomic, readwrite) CGPoint center; @property (nonatomic, readonly) CGRect bounds; @property (nonatomic, readwrite) CGAffineTransform transform; ! @end • All items animated by UIKit Dynamics must implement this protocol • Describe what UIKit Dynamics needs to animate an item • position: center • size: bounds
  • UIDynamicItem Protocol @protocol UIDynamicItem <NSObject> ! @property (nonatomic, readwrite) CGPoint center; @property (nonatomic, readonly) CGRect bounds; @property (nonatomic, readwrite) CGAffineTransform transform; ! @end • All items animated by UIKit Dynamics must implement this protocol • Describe what UIKit Dynamics needs to animate an item • position: center • size: bounds • angle: transform (only 2D-transform)
  • UIDynamicItem Protocol • center, bounds, and transform are read only once by UIKit
  • UIDynamicItem Protocol • center, bounds, and transform are read only once by UIKit • When adding the item to an animator for the first time
  • UIDynamicItem Protocol • center, bounds, and transform are read only once by UIKit • When adding the item to an animator for the first time • center and transform are set on every animation tick
  • UIDynamicItem Protocol • center, bounds, and transform are read only once by UIKit • When adding the item to an animator for the first time • center and transform are set on every animation tick • methods performances are critical
  • UIDynamicItem Protocol • center, bounds, and transform are read only once by UIKit • When adding the item to an animator for the first time • center and transform are set on every animation tick • methods performances are critical • After grab the initial state every external change to center, bounds, and transform will be ignored
  • UIDynamicItem Protocol • center, bounds, and transform are read only once by UIKit • When adding the item to an animator for the first time • center and transform are set on every animation tick • methods performances are critical • After grab the initial state every external change to center, bounds, and transform will be ignored • A dynamic item should always have a valid initial state
  • UIDynamicItem Protocol • center, bounds, and transform are read only once by UIKit • When adding the item to an animator for the first time • center and transform are set on every animation tick • methods performances are critical • After grab the initial state every external change to center, bounds, and transform will be ignored • A dynamic item should always have a valid initial state • need a size
  • UIDynamicItem Protocol • center, bounds, and transform are read only once by UIKit • When adding the item to an animator for the first time • center and transform are set on every animation tick • methods performances are critical • After grab the initial state every external change to center, bounds, and transform will be ignored • A dynamic item should always have a valid initial state • need a size • need a reasonable position
  • UIDynamicItem Protocol • All items animated by UIKit Dynamics must implement this protocol
  • UIDynamicItem Protocol • All items animated by UIKit Dynamics must implement this protocol • UIView conforms to protocol @interface UIView : UIResponder < NSCoding, UIAppearance, UIAppearanceContainer, UIDynamicItem > { ... }
  • UIDynamicItem Protocol • All items animated by UIKit Dynamics must implement this protocol • UIView conforms to protocol @interface UIView : UIResponder < NSCoding, UIAppearance, UIAppearanceContainer, UIDynamicItem > { ... } • UICollectionViewLayoutAttributes conforms to protocol @interface UICollectionViewLayoutAttributes : NSObject < NSCopying, UIDynamicItem > { ... }
  • UIDynamicItem Protocol • All items animated by UIKit Dynamics must implement this protocol • UIView conforms to protocol @interface UIView : UIResponder < NSCoding, UIAppearance, UIAppearanceContainer, UIDynamicItem > { ... } • UICollectionViewLayoutAttributes conforms to protocol @interface UICollectionViewLayoutAttributes : NSObject < NSCopying, UIDynamicItem > { ... } • Custom class can conform to protocol @interface DPDynamicObject : NSObject < UIDynamicItem > { ... }
  • Architecture UIDynamicAnimator Reference view UIDynamicBehavior UIDynamicBehavior UIDynamicBehavior View View View
  • Architecture UIDynamicAnimator Reference view UIDynamicBehavior UIDynamicBehavior UIDynamicBehavior NSObject" <UIDynamicItem> NSObject" <UIDynamicItem> NSObject" <UIDynamicItem>
  • Example 1: conform to UIDynamicItem @interface DPDynamicObject : NSObject <UIDynamicItem> ! @property (nonatomic, readwrite) CGPoint center; @property (nonatomic, readonly) CGRect bounds; @property (nonatomic, readwrite) CGAffineTransform transform; ! @end ! ! @implementation ! DPDynamicObject - (CGRect)bounds { return CGRectMake(0.0, 0.0, 100.0, 100.0); } ! - (CGPoint)center { return CGPointMake(50.0, 50.0); } ! - (void)setCenter:(CGPoint)center { NSLog(@"Center = %@", NSStringFromCGPoint(center)); } ! - (CGAffineTransform)transform { return CGAffineTransformIdentity; } ! - (void)setTransform:(CGAffineTransform)transform { NSLog(@"Transform = %@", NSStringFromCGAffineTransform(transform)); } ! @end
  • Example 1: conform to UIDynamicItem @interface DPDynamicObject : NSObject <UIDynamicItem> ! @property (nonatomic, readwrite) CGPoint center; @property (nonatomic, readonly) CGRect bounds; @property (nonatomic, readwrite) CGAffineTransform transform; ! @end ! ! @implementation ! DPDynamicObject - (CGRect)bounds { return CGRectMake(0.0, 0.0, 100.0, 100.0); } ! - (CGPoint)center { return CGPointMake(50.0, 50.0); } ! - (void)setCenter:(CGPoint)center { NSLog(@"Center = %@", NSStringFromCGPoint(center)); } ! - (CGAffineTransform)transform { return CGAffineTransformIdentity; } ! - (void)setTransform:(CGAffineTransform)transform { NSLog(@"Transform = %@", NSStringFromCGAffineTransform(transform)); } ! @end
  • Example 1: conform to UIDynamicItem @interface DPDynamicObject : NSObject <UIDynamicItem> ! @property (nonatomic, readwrite) CGPoint center; @property (nonatomic, readonly) CGRect bounds; @property (nonatomic, readwrite) CGAffineTransform transform; ! @end ! ! @implementation ! DPDynamicObject - (CGRect)bounds { return CGRectMake(0.0, 0.0, 100.0, 100.0); } ! - (CGPoint)center { return CGPointMake(50.0, 50.0); } ! - (void)setCenter:(CGPoint)center { NSLog(@"Center = %@", NSStringFromCGPoint(center)); } ! - (CGAffineTransform)transform { return CGAffineTransformIdentity; } ! - (void)setTransform:(CGAffineTransform)transform { NSLog(@"Transform = %@", NSStringFromCGAffineTransform(transform)); } ! @end
  • Example 1: conform to UIDynamicItem @interface DPDynamicObject : NSObject <UIDynamicItem> ! @property (nonatomic, readwrite) CGPoint center; @property (nonatomic, readonly) CGRect bounds; @property (nonatomic, readwrite) CGAffineTransform transform; ! @end ! ! @implementation ! DPDynamicObject - (CGRect)bounds { return CGRectMake(0.0, 0.0, 100.0, 100.0); } ! - (CGPoint)center { return CGPointMake(50.0, 50.0); } ! - (void)setCenter:(CGPoint)center { NSLog(@"Center = %@", NSStringFromCGPoint(center)); } ! - (CGAffineTransform)transform { return CGAffineTransformIdentity; } ! - (void)setTransform:(CGAffineTransform)transform { NSLog(@"Transform = %@", NSStringFromCGAffineTransform(transform)); } ! @end
  • Example 1: conform to UIDynamicItem @interface DPDynamicObject : NSObject <UIDynamicItem> ! @property (nonatomic, readwrite) CGPoint center; @property (nonatomic, readonly) CGRect bounds; @property (nonatomic, readwrite) CGAffineTransform transform; ! @end ! ! @implementation ! DPDynamicObject - (CGRect)bounds { return CGRectMake(0.0, 0.0, 100.0, 100.0); } ! - (CGPoint)center { return CGPointMake(50.0, 50.0); } ! - (void)setCenter:(CGPoint)center { NSLog(@"Center = %@", NSStringFromCGPoint(center)); } ! - (CGAffineTransform)transform { return CGAffineTransformIdentity; } ! - (void)setTransform:(CGAffineTransform)transform { NSLog(@"Transform = %@", NSStringFromCGAffineTransform(transform)); } ! @end
  • Example 1: conform to UIDynamicItem @interface DPDynamicItemProtocolViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator * animator; @property (strong, nonatomic) DPDynamicObject *dynamicObject; @end ! @implementation DPDynamicItemProtocolViewController ... ! - (void)viewDidLoad { [super viewDidLoad]; ! ! self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; self.dynamicObject = [[DPDynamicObject alloc] init]; UIGravityBehavior *g; g =[[UIGravityBehavior alloc] initWithItems: @[self.dynamicObject] ]; UIDynamicItemBehavior *b; b =[[UIDynamicItemBehavior alloc] initWithItems: @[self.dynamicObject] ]; b.elasticity = 0.5f; UICollisionBehavior *c; c =[[UICollisionBehavior alloc] initWithItems: @[self.dynamicObject] ]; c.translatesReferenceBoundsIntoBoundary = YES; [self.animator addBehavior:g]; [self.animator addBehavior:b]; [self.animator addBehavior:c]; } ... @end
  • Example 1: conform to UIDynamicItem @interface DPDynamicItemProtocolViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator * animator; @property (strong, nonatomic) DPDynamicObject *dynamicObject; @end ! @implementation DPDynamicItemProtocolViewController ... ! - (void)viewDidLoad { [super viewDidLoad]; ! ! self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; self.dynamicObject = [[DPDynamicObject alloc] init]; UIGravityBehavior *g; g =[[UIGravityBehavior alloc] initWithItems: @[self.dynamicObject] ]; UIDynamicItemBehavior *b; b =[[UIDynamicItemBehavior alloc] initWithItems: @[self.dynamicObject] ]; b.elasticity = 0.5f; UICollisionBehavior *c; c =[[UICollisionBehavior alloc] initWithItems: @[self.dynamicObject] ]; c.translatesReferenceBoundsIntoBoundary = YES; [self.animator addBehavior:g]; [self.animator addBehavior:b]; [self.animator addBehavior:c]; } ... @end
  • Example 1: conform to UIDynamicItem @interface DPDynamicItemProtocolViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator * animator; @property (strong, nonatomic) DPDynamicObject *dynamicObject; @end ! @implementation DPDynamicItemProtocolViewController ... ! - (void)viewDidLoad { [super viewDidLoad]; ! ! self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; self.dynamicObject = [[DPDynamicObject alloc] init]; UIGravityBehavior *g; g =[[UIGravityBehavior alloc] initWithItems: @[self.dynamicObject] ]; UIDynamicItemBehavior *b; b =[[UIDynamicItemBehavior alloc] initWithItems: @[self.dynamicObject] ]; b.elasticity = 0.5f; UICollisionBehavior *c; c =[[UICollisionBehavior alloc] initWithItems: @[self.dynamicObject] ]; c.translatesReferenceBoundsIntoBoundary = YES; [self.animator addBehavior:g]; [self.animator addBehavior:b]; [self.animator addBehavior:c]; } ... @end
  • Example 1: conform to UIDynamicItem @interface DPDynamicItemProtocolViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator * animator; @property (strong, nonatomic) DPDynamicObject *dynamicObject; @end ! @implementation DPDynamicItemProtocolViewController ... ! - (void)viewDidLoad { [super viewDidLoad]; ! ! self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; self.dynamicObject = [[DPDynamicObject alloc] init]; UIGravityBehavior *g; g =[[UIGravityBehavior alloc] initWithItems: @[self.dynamicObject] ]; UIDynamicItemBehavior *b; b =[[UIDynamicItemBehavior alloc] initWithItems: @[self.dynamicObject] ]; b.elasticity = 0.5f; UICollisionBehavior *c; c =[[UICollisionBehavior alloc] initWithItems: @[self.dynamicObject] ]; c.translatesReferenceBoundsIntoBoundary = YES; [self.animator addBehavior:g]; [self.animator addBehavior:b]; [self.animator addBehavior:c]; } ... @end
  • Example 1: conform to UIDynamicItem @interface DPDynamicItemProtocolViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator * animator; @property (strong, nonatomic) DPDynamicObject *dynamicObject; @end ! @implementation DPDynamicItemProtocolViewController ... ! - (void)viewDidLoad { [super viewDidLoad]; ! ! self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; self.dynamicObject = [[DPDynamicObject alloc] init]; UIGravityBehavior *g; g =[[UIGravityBehavior alloc] initWithItems: @[self.dynamicObject] ]; UIDynamicItemBehavior *b; b =[[UIDynamicItemBehavior alloc] initWithItems: @[self.dynamicObject] ]; b.elasticity = 0.5f; UICollisionBehavior *c; c =[[UICollisionBehavior alloc] initWithItems: @[self.dynamicObject] ]; c.translatesReferenceBoundsIntoBoundary = YES; [self.animator addBehavior:g]; [self.animator addBehavior:b]; [self.animator addBehavior:c]; } ... @end
  • Example 1: conform to UIDynamicItem @interface DPDynamicItemProtocolViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator * animator; @property (strong, nonatomic) DPDynamicObject *dynamicObject; @end ! @implementation DPDynamicItemProtocolViewController ... ! - (void)viewDidLoad { [super viewDidLoad]; ! ! self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; self.dynamicObject = [[DPDynamicObject alloc] init]; UIGravityBehavior *g; g =[[UIGravityBehavior alloc] initWithItems: @[self.dynamicObject] ]; UIDynamicItemBehavior *b; b =[[UIDynamicItemBehavior alloc] initWithItems: @[self.dynamicObject] ]; b.elasticity = 0.5f; UICollisionBehavior *c; c =[[UICollisionBehavior alloc] initWithItems: @[self.dynamicObject] ]; c.translatesReferenceBoundsIntoBoundary = YES; [self.animator addBehavior:g]; [self.animator addBehavior:b]; [self.animator addBehavior:c]; } ... @end
  • Example 1: conform to UIDynamicItem @interface DPDynamicItemProtocolViewController : UIViewController @property (strong, nonatomic) UIDynamicAnimator * animator; @property (strong, nonatomic) DPDynamicObject *dynamicObject; @end ! @implementation DPDynamicItemProtocolViewController ... ! - (void)viewDidLoad { [super viewDidLoad]; ! ! self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; self.dynamicObject = [[DPDynamicObject alloc] init]; UIGravityBehavior *g; g =[[UIGravityBehavior alloc] initWithItems: @[self.dynamicObject] ]; UIDynamicItemBehavior *b; b =[[UIDynamicItemBehavior alloc] initWithItems: @[self.dynamicObject] ]; b.elasticity = 0.5f; UICollisionBehavior *c; c =[[UICollisionBehavior alloc] initWithItems: @[self.dynamicObject] ]; c.translatesReferenceBoundsIntoBoundary = YES; [self.animator addBehavior:g]; [self.animator addBehavior:b]; [self.animator addBehavior:c]; } ... @end
  • Example 1: conform to UIDynamicItem
  • Example 1: conform to UIDynamicItem 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 ! 18:58:05.598 18:58:05.609 18:58:05.611 18:58:05.626 18:58:05.629 18:58:05.642 18:58:05.645 18:58:05.659 18:58:05.661 18:58:05.675 18:58:05.677 DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] Animator is running Center = {50, 50.04797} Transform = [1, 0, -0, 1, Center = {50, 50.447464} Transform = [1, 0, -0, 1, Center = {50, 51.054173} Transform = [1, 0, -0, 1, Center = {50, 51.915657} Transform = [1, 0, -0, 1, Center = {50, 53.031506} Transform = [1, 0, -0, 1, 18:58:08.742 18:58:08.744 18:58:08.759 18:58:08.761 18:58:08.775 18:58:08.777 18:58:08.792 18:58:08.794 18:58:08.809 18:58:08.810 18:58:08.812 DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] Center = {50, 518.13135} Transform = [1, 0, -0, 1, Center = {50, 518.13135} Transform = [1, 0, -0, 1, Center = {50, 518.13135} Transform = [1, 0, -0, 1, Center = {50, 518.13135} Transform = [1, 0, -0, 1, Center = {50, 518.13135} Transform = [1, 0, -0, 1, Animator is stopped 0, 0] 0, 0] 0, 0] 0, 0] 0, 0] ... ! 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 0, 0] 0, 0] 0, 0] 0, 0] 0, 0]
  • Example 1: conform to UIDynamicItem 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 ! 18:58:05.598 18:58:05.609 18:58:05.611 18:58:05.626 18:58:05.629 18:58:05.642 18:58:05.645 18:58:05.659 18:58:05.661 18:58:05.675 18:58:05.677 DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] Animator is running Center = {50, 50.04797} Transform = [1, 0, -0, 1, Center = {50, 50.447464} Transform = [1, 0, -0, 1, Center = {50, 51.054173} Transform = [1, 0, -0, 1, Center = {50, 51.915657} Transform = [1, 0, -0, 1, Center = {50, 53.031506} Transform = [1, 0, -0, 1, 18:58:08.742 18:58:08.744 18:58:08.759 18:58:08.761 18:58:08.775 18:58:08.777 18:58:08.792 18:58:08.794 18:58:08.809 18:58:08.810 18:58:08.812 DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] DynamicsPlayground[771:60b] Center = {50, 518.13135} Transform = [1, 0, -0, 1, Center = {50, 518.13135} Transform = [1, 0, -0, 1, Center = {50, 518.13135} Transform = [1, 0, -0, 1, Center = {50, 518.13135} Transform = [1, 0, -0, 1, Center = {50, 518.13135} Transform = [1, 0, -0, 1, Animator is stopped 0, 0] 0, 0] 0, 0] 0, 0] 0, 0] ... ! 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 2013-10-17 0, 0] 0, 0] 0, 0] 0, 0] 0, 0]
  • UIDynamicItem Use Case • Can use a single dynamic item to animate different views
  • UIDynamicItem Use Case • Can use a single dynamic item to animate different views • Can map center or transform to something else
  • UIDynamicItem Use Case • Can use a single dynamic item to animate different views • Can map center or transform to something else • To “animate” something that isnt’a a view or a collection view use a UIDynamicItem
  • UIDynamicItem Use Case • Can use a single dynamic item to animate different views • Can map center or transform to something else • To “animate” something that isnt’a a view or a collection view use a UIDynamicItem
  • Example 2: remap center property
  • Example 2: remap center property @protocol ResizableDynamicItem <UIDynamicItem> ! ! @interface APLPositionToBoundsMapping : NSObject <UIDynamicItem> ! - (instancetype)initWithTarget:(id<ResizableDynamicItem>)target; ! @end ! ! @protocol ResizableDynamicItem <UIDynamicItem> ! @property (nonatomic, readwrite) CGRect bounds; ! @end
  • Example 2: remap center property @protocol ResizableDynamicItem <UIDynamicItem> ! ! @interface APLPositionToBoundsMapping : NSObject <UIDynamicItem> ! - (instancetype)initWithTarget:(id<ResizableDynamicItem>)target; ! @end ! ! @protocol ResizableDynamicItem <UIDynamicItem> ! @property (nonatomic, readwrite) CGRect bounds; ! @end
  • Example 2: remap center property @protocol ResizableDynamicItem <UIDynamicItem> ! ! @interface APLPositionToBoundsMapping : NSObject <UIDynamicItem> ! - (instancetype)initWithTarget:(id<ResizableDynamicItem>)target; ! @end ! ! @protocol ResizableDynamicItem <UIDynamicItem> ! @property (nonatomic, readwrite) CGRect bounds; ! @end
  • Example 2: remap center property #import "APLPositionToBoundsMapping.h" ! @interface APLPositionToBoundsMapping () @property (nonatomic, strong) id<ResizableDynamicItem> target; @end ! @implementation ! APLPositionToBoundsMapping - (instancetype)initWithTarget:(id<ResizableDynamicItem>)target { if ((self = [super init])) { _target = target; } return self; } ! - (CGRect)bounds { return self.target.bounds; } // Pass through ! - (CGPoint)center { return CGPointMake(self.target.bounds.size.width, self.target.bounds.size.height); } ! - (void)setCenter:(CGPoint)center { self.target.bounds = CGRectMake(0, 0, center.x, center.y); } ! - (CGAffineTransform)transform { return self.target.transform; // Pass through } ! - (void)setTransform:(CGAffineTransform)transform { self.target.transform = transform; // Pass through } @end
  • Example 2: remap center property #import "APLPositionToBoundsMapping.h" ! @interface APLPositionToBoundsMapping () @property (nonatomic, strong) id<ResizableDynamicItem> target; @end ! @implementation ! APLPositionToBoundsMapping - (instancetype)initWithTarget:(id<ResizableDynamicItem>)target { if ((self = [super init])) { _target = target; } return self; } ! - (CGRect)bounds { return self.target.bounds; } // Pass through ! - (CGPoint)center { return CGPointMake(self.target.bounds.size.width, self.target.bounds.size.height); } ! - (void)setCenter:(CGPoint)center { self.target.bounds = CGRectMake(0, 0, center.x, center.y); } ! - (CGAffineTransform)transform { return self.target.transform; // Pass through } ! - (void)setTransform:(CGAffineTransform)transform { self.target.transform = transform; // Pass through } @end
  • Example 2: remap center property #import "APLPositionToBoundsMapping.h" ! @interface APLPositionToBoundsMapping () @property (nonatomic, strong) id<ResizableDynamicItem> target; @end ! @implementation ! APLPositionToBoundsMapping - (instancetype)initWithTarget:(id<ResizableDynamicItem>)target { if ((self = [super init])) { _target = target; } return self; } ! - (CGRect)bounds { return self.target.bounds; } // Pass through ! - (CGPoint)center { return CGPointMake(self.target.bounds.size.width, self.target.bounds.size.height); } ! - (void)setCenter:(CGPoint)center { self.target.bounds = CGRectMake(0, 0, center.x, center.y); } ! - (CGAffineTransform)transform { return self.target.transform; // Pass through } ! - (void)setTransform:(CGAffineTransform)transform { self.target.transform = transform; // Pass through } @end
  • Example 2: remap center property #import "APLPositionToBoundsMapping.h" ! @interface APLPositionToBoundsMapping () @property (nonatomic, strong) id<ResizableDynamicItem> target; @end ! @implementation ! APLPositionToBoundsMapping - (instancetype)initWithTarget:(id<ResizableDynamicItem>)target { if ((self = [super init])) { _target = target; } return self; } ! - (CGRect)bounds { return self.target.bounds; } // Pass through ! - (CGPoint)center { return CGPointMake(self.target.bounds.size.width, self.target.bounds.size.height); } ! - (void)setCenter:(CGPoint)center { self.target.bounds = CGRectMake(0, 0, center.x, center.y); } ! - (CGAffineTransform)transform { return self.target.transform; // Pass through } ! - (void)setTransform:(CGAffineTransform)transform { self.target.transform = transform; // Pass through } @end
  • Example 2: remap center property @import UIKit; ! ! @interface APLCustomDynamicItemViewController : UIViewController @end ! ! @interface APLCustomDynamicItemViewController () @property (nonatomic, weak) IBOutlet UIButton *button1; @property (nonatomic, readwrite) CGRect button1Bounds; @property (nonatomic, strong) UIDynamicAnimator *animator; @end ! ! @implementation APLCustomDynamicItemViewController ! - (void)viewDidLoad { ! // Save the button's initial bounds. self.button1Bounds = self.button1.bounds; // Force the button image to scale with its bounds. self.button1.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill; self.button1.contentVerticalAlignment = UIControlContentHorizontalAlignmentFill; } ! // ... continue ! @end
  • Example 2: remap center property @import UIKit; ! ! @interface APLCustomDynamicItemViewController : UIViewController @end ! ! @interface APLCustomDynamicItemViewController () @property (nonatomic, weak) IBOutlet UIButton *button1; @property (nonatomic, readwrite) CGRect button1Bounds; @property (nonatomic, strong) UIDynamicAnimator *animator; @end ! ! @implementation APLCustomDynamicItemViewController ! - (void)viewDidLoad { ! // Save the button's initial bounds. self.button1Bounds = self.button1.bounds; // Force the button image to scale with its bounds. self.button1.contentHorizontalAlignment = UIControlContentHorizontalAlignmentFill; self.button1.contentVerticalAlignment = UIControlContentHorizontalAlignmentFill; } ! // ... continue ! @end
  • Example 2: remap center property ! @implementation APLCustomDynamicItemViewController ! ... ! - (IBAction)buttonAction:(id)sender { ! // Reset the buttons bounds to their initial state. self.button1.bounds = self.button1Bounds; UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; ! ! APLPositionToBoundsMapping *buttonBoundsDynamicItem; buttonBoundsDynamicItem =[[APLPositionToBoundsMapping alloc] initWithTarget:sender]; UIAttachmentBehavior *attachment; attachment = [[UIAttachmentBehavior alloc] initWithItem:buttonBoundsDynamicItem attachedToAnchor:buttonBoundsDynamicItem.center]; [attachment setFrequency:2.0]; [attachment setDamping:0.3]; [animator addBehavior:attachment]; UIPushBehavior *pushBehavior; pushBehavior = [[UIPushBehavior alloc] initWithItems:@[buttonBoundsDynamicItem] mode:UIPushBehaviorModeInstantaneous]; pushBehavior.angle = M_PI_4; pushBehavior.magnitude = 2.0; [animator addBehavior:pushBehavior]; self.animator = animator; } @end
  • Example 2: remap center property ! @implementation APLCustomDynamicItemViewController ! ... ! - (IBAction)buttonAction:(id)sender { ! // Reset the buttons bounds to their initial state. self.button1.bounds = self.button1Bounds; UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; ! ! APLPositionToBoundsMapping *buttonBoundsDynamicItem; buttonBoundsDynamicItem =[[APLPositionToBoundsMapping alloc] initWithTarget:sender]; UIAttachmentBehavior *attachment; attachment = [[UIAttachmentBehavior alloc] initWithItem:buttonBoundsDynamicItem attachedToAnchor:buttonBoundsDynamicItem.center]; [attachment setFrequency:2.0]; [attachment setDamping:0.3]; [animator addBehavior:attachment]; UIPushBehavior *pushBehavior; pushBehavior = [[UIPushBehavior alloc] initWithItems:@[buttonBoundsDynamicItem] mode:UIPushBehaviorModeInstantaneous]; pushBehavior.angle = M_PI_4; pushBehavior.magnitude = 2.0; [animator addBehavior:pushBehavior]; self.animator = animator; } @end
  • Example 2: remap center property ! @implementation APLCustomDynamicItemViewController ! ... ! - (IBAction)buttonAction:(id)sender { ! // Reset the buttons bounds to their initial state. self.button1.bounds = self.button1Bounds; UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; ! ! APLPositionToBoundsMapping *buttonBoundsDynamicItem; buttonBoundsDynamicItem =[[APLPositionToBoundsMapping alloc] initWithTarget:sender]; UIAttachmentBehavior *attachment; attachment = [[UIAttachmentBehavior alloc] initWithItem:buttonBoundsDynamicItem attachedToAnchor:buttonBoundsDynamicItem.center]; [attachment setFrequency:2.0]; [attachment setDamping:0.3]; [animator addBehavior:attachment]; UIPushBehavior *pushBehavior; pushBehavior = [[UIPushBehavior alloc] initWithItems:@[buttonBoundsDynamicItem] mode:UIPushBehaviorModeInstantaneous]; pushBehavior.angle = M_PI_4; pushBehavior.magnitude = 2.0; [animator addBehavior:pushBehavior]; self.animator = animator; } @end
  • Example 2: remap center property ! @implementation APLCustomDynamicItemViewController ! ... ! - (IBAction)buttonAction:(id)sender { ! // Reset the buttons bounds to their initial state. self.button1.bounds = self.button1Bounds; UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; ! ! APLPositionToBoundsMapping *buttonBoundsDynamicItem; buttonBoundsDynamicItem =[[APLPositionToBoundsMapping alloc] initWithTarget:sender]; UIAttachmentBehavior *attachment; attachment = [[UIAttachmentBehavior alloc] initWithItem:buttonBoundsDynamicItem attachedToAnchor:buttonBoundsDynamicItem.center]; [attachment setFrequency:2.0]; [attachment setDamping:0.3]; [animator addBehavior:attachment]; UIPushBehavior *pushBehavior; pushBehavior = [[UIPushBehavior alloc] initWithItems:@[buttonBoundsDynamicItem] mode:UIPushBehaviorModeInstantaneous]; pushBehavior.angle = M_PI_4; pushBehavior.magnitude = 2.0; [animator addBehavior:pushBehavior]; self.animator = animator; } @end
  • Example 2: remap center property ! @implementation APLCustomDynamicItemViewController ! ... ! - (IBAction)buttonAction:(id)sender { ! // Reset the buttons bounds to their initial state. self.button1.bounds = self.button1Bounds; UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; ! ! APLPositionToBoundsMapping *buttonBoundsDynamicItem; buttonBoundsDynamicItem =[[APLPositionToBoundsMapping alloc] initWithTarget:sender]; UIAttachmentBehavior *attachment; attachment = [[UIAttachmentBehavior alloc] initWithItem:buttonBoundsDynamicItem attachedToAnchor:buttonBoundsDynamicItem.center]; [attachment setFrequency:2.0]; [attachment setDamping:0.3]; [animator addBehavior:attachment]; UIPushBehavior *pushBehavior; pushBehavior = [[UIPushBehavior alloc] initWithItems:@[buttonBoundsDynamicItem] mode:UIPushBehaviorModeInstantaneous]; pushBehavior.angle = M_PI_4; pushBehavior.magnitude = 2.0; [animator addBehavior:pushBehavior]; self.animator = animator; } @end
  • Example 2: remap center property ! @implementation APLCustomDynamicItemViewController ! ... ! - (IBAction)buttonAction:(id)sender { ! // Reset the buttons bounds to their initial state. self.button1.bounds = self.button1Bounds; UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; ! ! APLPositionToBoundsMapping *buttonBoundsDynamicItem; buttonBoundsDynamicItem =[[APLPositionToBoundsMapping alloc] initWithTarget:sender]; UIAttachmentBehavior *attachment; attachment = [[UIAttachmentBehavior alloc] initWithItem:buttonBoundsDynamicItem attachedToAnchor:buttonBoundsDynamicItem.center]; [attachment setFrequency:2.0]; [attachment setDamping:0.3]; [animator addBehavior:attachment]; UIPushBehavior *pushBehavior; pushBehavior = [[UIPushBehavior alloc] initWithItems:@[buttonBoundsDynamicItem] mode:UIPushBehaviorModeInstantaneous]; pushBehavior.angle = M_PI_4; pushBehavior.magnitude = 2.0; [animator addBehavior:pushBehavior]; self.animator = animator; } @end
  • Example 2: remap center property ! @implementation APLCustomDynamicItemViewController ! ... ! - (IBAction)buttonAction:(id)sender { ! // Reset the buttons bounds to their initial state. self.button1.bounds = self.button1Bounds; UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; ! ! APLPositionToBoundsMapping *buttonBoundsDynamicItem; buttonBoundsDynamicItem =[[APLPositionToBoundsMapping alloc] initWithTarget:sender]; UIAttachmentBehavior *attachment; attachment = [[UIAttachmentBehavior alloc] initWithItem:buttonBoundsDynamicItem attachedToAnchor:buttonBoundsDynamicItem.center]; [attachment setFrequency:2.0]; [attachment setDamping:0.3]; [animator addBehavior:attachment]; UIPushBehavior *pushBehavior; pushBehavior = [[UIPushBehavior alloc] initWithItems:@[buttonBoundsDynamicItem] mode:UIPushBehaviorModeInstantaneous]; pushBehavior.angle = M_PI_4; pushBehavior.magnitude = 2.0; [animator addBehavior:pushBehavior]; self.animator = animator; } @end
  • Example 2: remap center property
  • Example 2: remap center property 19:18:56.545 19:18:56.547 19:18:56.549 19:18:56.550 19:18:56.551 19:18:56.552 19:18:56.553 19:18:56.556 19:18:56.561 19:18:56.563 19:18:56.575 19:18:56.578 -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping Animator is running -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping center]:68 {150, 46} center]:68 {150, 46} bounds]:55 {{0, 0}, {150, 46}} bounds]:55 {{0, 0}, {150, 46}} bounds]:55 {{0, 0}, {150, 46}} transform]:94 [1, -1.3833854e-06, 1.3833854e-06, 1, 0, 0] transform]:94 [1, -1.3833854e-06, 1.3833854e-06, 1, 0, 0] 19:19:02.527 19:19:02.529 19:19:02.542 19:19:02.545 19:19:02.547 -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping Animator stopped setCenter:]:81 {150.07957, 46.079357} setTransform:]:107 [1, -2.7647307e-06, 2.7647307e-06, 1, 0, 0] setCenter:]:81 {150.07266, 46.072491} setTransform:]:107 [1, -2.7667704e-06, 2.7667704e-06, 1, 0, 0] ! ... ! setCenter:]:81 {150, 45.999996} setTransform:]:107 [1, -1.3833854e-06, 1.3833854e-06, 1, 0, 0] setCenter:]:81 {153.80513, 49.805138} setTransform:]:107 [1, -1.3838192e-06, 1.3838192e-06, 1, 0, 0]
  • Example 2: remap center property 19:18:56.545 19:18:56.547 19:18:56.549 19:18:56.550 19:18:56.551 19:18:56.552 19:18:56.553 19:18:56.556 19:18:56.561 19:18:56.563 19:18:56.575 19:18:56.578 -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping Animator is running -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping center]:68 {150, 46} center]:68 {150, 46} bounds]:55 {{0, 0}, {150, 46}} bounds]:55 {{0, 0}, {150, 46}} bounds]:55 {{0, 0}, {150, 46}} transform]:94 [1, -1.3833854e-06, 1.3833854e-06, 1, 0, 0] transform]:94 [1, -1.3833854e-06, 1.3833854e-06, 1, 0, 0] 19:19:02.527 19:19:02.529 19:19:02.542 19:19:02.545 19:19:02.547 -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping Animator stopped setCenter:]:81 {150.07957, 46.079357} setTransform:]:107 [1, -2.7647307e-06, 2.7647307e-06, 1, 0, 0] setCenter:]:81 {150.07266, 46.072491} setTransform:]:107 [1, -2.7667704e-06, 2.7667704e-06, 1, 0, 0] ! ... ! setCenter:]:81 {150, 45.999996} setTransform:]:107 [1, -1.3833854e-06, 1.3833854e-06, 1, 0, 0] setCenter:]:81 {153.80513, 49.805138} setTransform:]:107 [1, -1.3838192e-06, 1.3838192e-06, 1, 0, 0]
  • Example 2: remap center property 19:18:56.545 19:18:56.547 19:18:56.549 19:18:56.550 19:18:56.551 19:18:56.552 19:18:56.553 19:18:56.556 19:18:56.561 19:18:56.563 19:18:56.575 19:18:56.578 -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping Animator is running -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping center]:68 {150, 46} center]:68 {150, 46} bounds]:55 {{0, 0}, {150, 46}} bounds]:55 {{0, 0}, {150, 46}} bounds]:55 {{0, 0}, {150, 46}} transform]:94 [1, -1.3833854e-06, 1.3833854e-06, 1, 0, 0] transform]:94 [1, -1.3833854e-06, 1.3833854e-06, 1, 0, 0] 19:19:02.527 19:19:02.529 19:19:02.542 19:19:02.545 19:19:02.547 -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping Animator stopped setCenter:]:81 {150.07957, 46.079357} setTransform:]:107 [1, -2.7647307e-06, 2.7647307e-06, 1, 0, 0] setCenter:]:81 {150.07266, 46.072491} setTransform:]:107 [1, -2.7667704e-06, 2.7667704e-06, 1, 0, 0] ! ... ! setCenter:]:81 {150, 45.999996} setTransform:]:107 [1, -1.3833854e-06, 1.3833854e-06, 1, 0, 0] setCenter:]:81 {153.80513, 49.805138} setTransform:]:107 [1, -1.3838192e-06, 1.3838192e-06, 1, 0, 0]
  • Example 2: remap center property 19:18:56.545 19:18:56.547 19:18:56.549 19:18:56.550 19:18:56.551 19:18:56.552 19:18:56.553 19:18:56.556 19:18:56.561 19:18:56.563 19:18:56.575 19:18:56.578 -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping Animator is running -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping center]:68 {150, 46} center]:68 {150, 46} bounds]:55 {{0, 0}, {150, 46}} bounds]:55 {{0, 0}, {150, 46}} bounds]:55 {{0, 0}, {150, 46}} transform]:94 [1, -1.3833854e-06, 1.3833854e-06, 1, 0, 0] transform]:94 [1, -1.3833854e-06, 1.3833854e-06, 1, 0, 0] 19:19:02.527 19:19:02.529 19:19:02.542 19:19:02.545 19:19:02.547 -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping Animator stopped setCenter:]:81 {150.07957, 46.079357} setTransform:]:107 [1, -2.7647307e-06, 2.7647307e-06, 1, 0, 0] setCenter:]:81 {150.07266, 46.072491} setTransform:]:107 [1, -2.7667704e-06, 2.7667704e-06, 1, 0, 0] ! ... ! setCenter:]:81 {150, 45.999996} setTransform:]:107 [1, -1.3833854e-06, 1.3833854e-06, 1, 0, 0] setCenter:]:81 {153.80513, 49.805138} setTransform:]:107 [1, -1.3838192e-06, 1.3838192e-06, 1, 0, 0]
  • Example 2: remap center property 19:18:56.545 19:18:56.547 19:18:56.549 19:18:56.550 19:18:56.551 19:18:56.552 19:18:56.553 19:18:56.556 19:18:56.561 19:18:56.563 19:18:56.575 19:18:56.578 -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping Animator is running -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping center]:68 {150, 46} center]:68 {150, 46} bounds]:55 {{0, 0}, {150, 46}} bounds]:55 {{0, 0}, {150, 46}} bounds]:55 {{0, 0}, {150, 46}} transform]:94 [1, -1.3833854e-06, 1.3833854e-06, 1, 0, 0] transform]:94 [1, -1.3833854e-06, 1.3833854e-06, 1, 0, 0] 19:19:02.527 19:19:02.529 19:19:02.542 19:19:02.545 19:19:02.547 -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping Animator stopped setCenter:]:81 {150.07957, 46.079357} setTransform:]:107 [1, -2.7647307e-06, 2.7647307e-06, 1, 0, 0] setCenter:]:81 {150.07266, 46.072491} setTransform:]:107 [1, -2.7667704e-06, 2.7667704e-06, 1, 0, 0] ! ... ! setCenter:]:81 {150, 45.999996} setTransform:]:107 [1, -1.3833854e-06, 1.3833854e-06, 1, 0, 0] setCenter:]:81 {153.80513, 49.805138} setTransform:]:107 [1, -1.3838192e-06, 1.3838192e-06, 1, 0, 0]
  • Example 2: remap center property 19:18:56.545 19:18:56.547 19:18:56.549 19:18:56.550 19:18:56.551 19:18:56.552 19:18:56.553 19:18:56.556 19:18:56.561 19:18:56.563 19:18:56.575 19:18:56.578 -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping Animator is running -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping center]:68 {150, 46} center]:68 {150, 46} bounds]:55 {{0, 0}, {150, 46}} bounds]:55 {{0, 0}, {150, 46}} bounds]:55 {{0, 0}, {150, 46}} transform]:94 [1, -1.3833854e-06, 1.3833854e-06, 1, 0, 0] transform]:94 [1, -1.3833854e-06, 1.3833854e-06, 1, 0, 0] 19:19:02.527 19:19:02.529 19:19:02.542 19:19:02.545 19:19:02.547 -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping -[APLPositionToBoundsMapping Animator stopped setCenter:]:81 {150.07957, 46.079357} setTransform:]:107 [1, -2.7647307e-06, 2.7647307e-06, 1, 0, 0] setCenter:]:81 {150.07266, 46.072491} setTransform:]:107 [1, -2.7667704e-06, 2.7667704e-06, 1, 0, 0] ! ... ! setCenter:]:81 {150, 45.999996} setTransform:]:107 [1, -1.3833854e-06, 1.3833854e-06, 1, 0, 0] setCenter:]:81 {153.80513, 49.805138} setTransform:]:107 [1, -1.3838192e-06, 1.3838192e-06, 1, 0, 0]
  • Dynamics & Collection View
  • Dynamics & UICollectionViews • UICollectionViewLayoutAttributes conform to UIDynamicItem
  • Dynamics & UICollectionViews • UICollectionViewLayoutAttributes conform to UIDynamicItem • Can use UIKit Dynamics with collection view
  • Dynamics & UICollectionViews • UICollectionViewLayoutAttributes conform to UIDynamicItem • Can use UIKit Dynamics with collection view • How
  • Dynamics & UICollectionViews • UICollectionViewLayoutAttributes conform to UIDynamicItem • Can use UIKit Dynamics with collection view • How • Use UIKit Dynamics for very specific animations
  • Dynamics & UICollectionViews • UICollectionViewLayoutAttributes conform to UIDynamicItem • Can use UIKit Dynamics with collection view • How • Use UIKit Dynamics for very specific animations • create UIDynamicAnimator as needed and discard later
  • Dynamics & UICollectionViews • UICollectionViewLayoutAttributes conform to UIDynamicItem • Can use UIKit Dynamics with collection view • How • Use UIKit Dynamics for very specific animations • create UIDynamicAnimator as needed and discard later • Animate a subset of a layout
  • Dynamics & UICollectionViews • UICollectionViewLayoutAttributes conform to UIDynamicItem • Can use UIKit Dynamics with collection view • How • Use UIKit Dynamics for very specific animations • create UIDynamicAnimator as needed and discard later • Animate a subset of a layout • Build an entire layout with UIKit Dynamics
  • Dynamics & UICollectionViews • UICollectionViewLayoutAttributes conform to UIDynamicItem • Can use UIKit Dynamics with collection view • How • Use UIKit Dynamics for very specific animations • create UIDynamicAnimator as needed and discard later • Animate a subset of a layout • Build an entire layout with UIKit Dynamics • performace: better for small data source
  • Basic steps • Create the the UICollectionViewLayout instance
  • Basic steps • Create the the UICollectionViewLayout instance • Create the UIDynamicAnimator with layout instance UICollectionViewLayout *layout = ...; animator = [[UIDynamicAnimator alloc] initWithCollectionViewLayout :layout];
  • Basic steps • Create the the UICollectionViewLayout instance • Create the UIDynamicAnimator with layout instance UICollectionViewLayout *layout = ...; animator = [[UIDynamicAnimator alloc] initWithCollectionViewLayout :layout];
  • Basic steps • Create the the UICollectionViewLayout instance • Create the UIDynamicAnimator with layout instance UICollectionViewLayout *layout = ...; animator = [[UIDynamicAnimator alloc] initWithCollectionViewLayout :layout];
  • Basic steps • Create the the UICollectionViewLayout instance • Create the UIDynamicAnimator with layout instance UICollectionViewLayout *layout = ...; animator = [[UIDynamicAnimator alloc] initWithCollectionViewLayout :layout];
  • Basic steps • Create the the UICollectionViewLayout instance • Create the UIDynamicAnimator with layout instance UICollectionViewLayout *layout = ...; animator = [[UIDynamicAnimator alloc] initWithCollectionViewLayout :layout]; • Create behaviors and add UICollectionViewLayoutAttributes to these behaviors
  • Basic steps • Create the the UICollectionViewLayout instance • Create the UIDynamicAnimator with layout instance UICollectionViewLayout *layout = ...; animator = [[UIDynamicAnimator alloc] initWithCollectionViewLayout :layout]; • Create behaviors and add UICollectionViewLayoutAttributes to these behaviors UICollectionViewLayoutAttributes *attribute = ...; UIAttachmentBehavior *spring; spring = [[UIAttachmentBehavior alloc] initWithItem:attribute attachedToAnchor:anchorPoint]; ...
  • Basic steps • Create the the UICollectionViewLayout instance • Create the UIDynamicAnimator with layout instance UICollectionViewLayout *layout = ...; animator = [[UIDynamicAnimator alloc] initWithCollectionViewLayout :layout]; • Create behaviors and add UICollectionViewLayoutAttributes to these behaviors UICollectionViewLayoutAttributes *attribute = ...; UIAttachmentBehavior *spring; spring = [[UIAttachmentBehavior alloc] initWithItem:attribute attachedToAnchor:anchorPoint]; ...
  • Basic steps • Create the the UICollectionViewLayout instance • Create the UIDynamicAnimator with layout instance UICollectionViewLayout *layout = ...; animator = [[UIDynamicAnimator alloc] initWithCollectionViewLayout :layout]; • Create behaviors and add UICollectionViewLayoutAttributes to these behaviors UICollectionViewLayoutAttributes *attribute = ...; UIAttachmentBehavior *spring; spring = [[UIAttachmentBehavior alloc] initWithItem:attribute attachedToAnchor:anchorPoint]; ...
  • UIKit Dynamics Support for UICollectionViews
  • UIKit Dynamics Support for UICollectionViews Dynamics has convenience support for UICollectionView
  • UIKit Dynamics Support for UICollectionViews Dynamics has convenience support for UICollectionView • Dynamics automatically invalidate layout as needed
  • UIKit Dynamics Support for UICollectionViews Dynamics has convenience support for UICollectionView • Dynamics automatically invalidate layout as needed • Dynamics pause the animator when a UICollectionViewLayout is no longer associated with the UICollectionView
  • UIKit Dynamics Support for UICollectionViews Dynamics has convenience support for UICollectionView • Dynamics automatically invalidate layout as needed • Dynamics pause the animator when a UICollectionViewLayout is no longer associated with the UICollectionView • provide conveniece method to implemement custom layout UIDynamicAnimator
  • UIKit Dynamics Support for UICollectionViews Dynamics has convenience support for UICollectionView • Dynamics automatically invalidate layout as needed • Dynamics pause the animator when a UICollectionViewLayout is no longer associated with the UICollectionView • provide conveniece method to implemement custom layout UIDynamicAnimator - (UICollectionViewLayoutAttributes*)layoutAttributesForCellAtIndexPath: (NSIndexPath*)ip;
  • UIKit Dynamics Support for UICollectionViews Dynamics has convenience support for UICollectionView • Dynamics automatically invalidate layout as needed • Dynamics pause the animator when a UICollectionViewLayout is no longer associated with the UICollectionView • provide conveniece method to implemement custom layout UIDynamicAnimator - (UICollectionViewLayoutAttributes*)layoutAttributesForCellAtIndexPath: (NSIndexPath*)ip; (UICollectionViewLayoutAttributes*)layoutAttributesForSupplementaryViewOfKind: (NSString *)k atIndexPath:(NSIndexPath *)ip;
  • UIKit Dynamics Support for UICollectionViews Dynamics has convenience support for UICollectionView • Dynamics automatically invalidate layout as needed • Dynamics pause the animator when a UICollectionViewLayout is no longer associated with the UICollectionView • provide conveniece method to implemement custom layout UIDynamicAnimator - (UICollectionViewLayoutAttributes*)layoutAttributesForCellAtIndexPath: (NSIndexPath*)ip; (UICollectionViewLayoutAttributes*)layoutAttributesForSupplementaryViewOfKind: (NSString *)k atIndexPath:(NSIndexPath *)ip; - (UICollectionViewLayoutAttributes*)layoutAttributesForDecorationViewOfKind: (NSString*)k atIndexPath:(NSIndexPath *)ip;
  • Collection View Layout Updates
  • Collection View Layout Updates Use usual UICollectionViewLayout methods for layout update: 
  • Collection View Layout Updates Use usual UICollectionViewLayout methods for layout update:  • prepareLayout
  • Collection View Layout Updates Use usual UICollectionViewLayout methods for layout update:  • prepareLayout •used when instantiate an animator or create initial state 
  • Collection View Layout Updates Use usual UICollectionViewLayout methods for layout update:  • prepareLayout •used when instantiate an animator or create initial state  •prepareForCollectionViewUpdates
  • Collection View Layout Updates Use usual UICollectionViewLayout methods for layout update:  • prepareLayout •used when instantiate an animator or create initial state  •prepareForCollectionViewUpdates •opportunity to add behaviors. UICollectionViewLayoutAttributes to
  • Collection View Layout Updates Use usual UICollectionViewLayout methods for layout update:  • prepareLayout •used when instantiate an animator or create initial state  •prepareForCollectionViewUpdates •opportunity to add UICollectionViewLayoutAttributes behaviors. • layoutAttributesForElementsInRect to
  • Collection View Layout Updates Use usual UICollectionViewLayout methods for layout update:  • prepareLayout •used when instantiate an animator or create initial state  •prepareForCollectionViewUpdates •opportunity to add UICollectionViewLayoutAttributes behaviors. • layoutAttributesForElementsInRect • UIDynamicAnimator has itemsInRect to
  • Example: collection view
  • Example: collection view @interface DPProportionalSpringFlowLayout : UICollectionViewFlowLayout @end ! ! ! @interface DPProportionalSpringFlowLayout () ! @property (strong, readwrite, nonatomic) UIDynamicAnimator ! @end ! @implementation DPProportionalSpringFlowLayout ! *dynamicAnimator; - (CGSize)itemSize { return CGSizeMake(CGRectGetWidth(self.collectionView.frame), 50.0f); } ! - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { return [self.dynamicAnimator itemsInRect:rect]; } ! - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { return [self.dynamicAnimator layoutAttributesForCellAtIndexPath:indexPath]; } ! ... ! @end // continue
  • Example: collection view @interface DPProportionalSpringFlowLayout : UICollectionViewFlowLayout @end ! ! ! @interface DPProportionalSpringFlowLayout () ! @property (strong, readwrite, nonatomic) UIDynamicAnimator ! @end ! @implementation DPProportionalSpringFlowLayout ! *dynamicAnimator; - (CGSize)itemSize { return CGSizeMake(CGRectGetWidth(self.collectionView.frame), 50.0f); } ! - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { return [self.dynamicAnimator itemsInRect:rect]; } ! - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { return [self.dynamicAnimator layoutAttributesForCellAtIndexPath:indexPath]; } ! ... ! @end // continue
  • Example: collection view @interface DPProportionalSpringFlowLayout : UICollectionViewFlowLayout @end ! ! ! @interface DPProportionalSpringFlowLayout () ! @property (strong, readwrite, nonatomic) UIDynamicAnimator ! @end ! @implementation DPProportionalSpringFlowLayout ! *dynamicAnimator; - (CGSize)itemSize { return CGSizeMake(CGRectGetWidth(self.collectionView.frame), 50.0f); } ! - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { return [self.dynamicAnimator itemsInRect:rect]; } ! - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { return [self.dynamicAnimator layoutAttributesForCellAtIndexPath:indexPath]; } ! ... ! @end // continue
  • Example: collection view @interface DPProportionalSpringFlowLayout : UICollectionViewFlowLayout @end ! ! ! @interface DPProportionalSpringFlowLayout () ! @property (strong, readwrite, nonatomic) UIDynamicAnimator ! @end ! @implementation DPProportionalSpringFlowLayout ! *dynamicAnimator; - (CGSize)itemSize { return CGSizeMake(CGRectGetWidth(self.collectionView.frame), 50.0f); } ! - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { return [self.dynamicAnimator itemsInRect:rect]; } ! - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { return [self.dynamicAnimator layoutAttributesForCellAtIndexPath:indexPath]; } ! ... ! @end // continue
  • Example: collection view @interface DPProportionalSpringFlowLayout : UICollectionViewFlowLayout @end ! ! ! @interface DPProportionalSpringFlowLayout () ! @property (strong, readwrite, nonatomic) UIDynamicAnimator ! @end ! @implementation DPProportionalSpringFlowLayout ! *dynamicAnimator; - (CGSize)itemSize { return CGSizeMake(CGRectGetWidth(self.collectionView.frame), 50.0f); } ! - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { return [self.dynamicAnimator itemsInRect:rect]; } ! - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { return [self.dynamicAnimator layoutAttributesForCellAtIndexPath:indexPath]; } ! ... ! @end // continue
  • Example: collection view @interface DPProportionalSpringFlowLayout : UICollectionViewFlowLayout @end ! ! ! @interface DPProportionalSpringFlowLayout () ! @property (strong, readwrite, nonatomic) UIDynamicAnimator ! @end ! @implementation DPProportionalSpringFlowLayout ! *dynamicAnimator; - (CGSize)itemSize { return CGSizeMake(CGRectGetWidth(self.collectionView.frame), 50.0f); } ! - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect { return [self.dynamicAnimator itemsInRect:rect]; } ! - (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath { return [self.dynamicAnimator layoutAttributesForCellAtIndexPath:indexPath]; } ! ... ! @end // continue
  • Example: collection view @implementation DPProportionalSpringFlowLayout ! // ! ... continue from previous slide - (void)prepareLayout { [super prepareLayout]; ! ! ! if (nil == [self dynamicAnimator]) { self.dynamicAnimator = [[UIDynamicAnimator alloc] initWithCollectionViewLayout:self]; CGSize contentSize = [self collectionViewContentSize]; CGRect contentRect = { CGPointZero, contentSize }; ! NSArray *layoutAttributes = [super layoutAttributesForElementsInRect:contentRect]; // create spring behavior for each item for (UICollectionViewLayoutAttributes *attribute in layoutAttributes) { ! } ! // ! UIAttachmentBehavior *springBehavior; springBehavior = [[UIAttachmentBehavior alloc] initWithItem:attribute attachedToAnchor:[attribute center]]; springBehavior.length = 0.0; springBehavior.damping = 0.5; springBehavior.frequency = 0.8; } } [self.dynamicAnimator addBehavior:springBehavior]; ... continue @end
  • Example: collection view @implementation DPProportionalSpringFlowLayout ! // ! ... continue from previous slide - (void)prepareLayout { [super prepareLayout]; ! ! ! if (nil == [self dynamicAnimator]) { self.dynamicAnimator = [[UIDynamicAnimator alloc] initWithCollectionViewLayout:self]; CGSize contentSize = [self collectionViewContentSize]; CGRect contentRect = { CGPointZero, contentSize }; ! NSArray *layoutAttributes = [super layoutAttributesForElementsInRect:contentRect]; // create spring behavior for each item for (UICollectionViewLayoutAttributes *attribute in layoutAttributes) { ! } ! // ! UIAttachmentBehavior *springBehavior; springBehavior = [[UIAttachmentBehavior alloc] initWithItem:attribute attachedToAnchor:[attribute center]]; springBehavior.length = 0.0; springBehavior.damping = 0.5; springBehavior.frequency = 0.8; } } [self.dynamicAnimator addBehavior:springBehavior]; ... continue @end
  • Example: collection view @implementation DPProportionalSpringFlowLayout ! // ! ... continue from previous slide - (void)prepareLayout { [super prepareLayout]; ! ! ! if (nil == [self dynamicAnimator]) { self.dynamicAnimator = [[UIDynamicAnimator alloc] initWithCollectionViewLayout:self]; CGSize contentSize = [self collectionViewContentSize]; CGRect contentRect = { CGPointZero, contentSize }; ! NSArray *layoutAttributes = [super layoutAttributesForElementsInRect:contentRect]; // create spring behavior for each item for (UICollectionViewLayoutAttributes *attribute in layoutAttributes) { ! } ! // ! UIAttachmentBehavior *springBehavior; springBehavior = [[UIAttachmentBehavior alloc] initWithItem:attribute attachedToAnchor:[attribute center]]; springBehavior.length = 0.0; springBehavior.damping = 0.5; springBehavior.frequency = 0.8; } } [self.dynamicAnimator addBehavior:springBehavior]; ... continue @end
  • Example: collection view @implementation DPProportionalSpringFlowLayout ! // ! ... continue from previous slide - (void)prepareLayout { [super prepareLayout]; ! ! ! if (nil == [self dynamicAnimator]) { self.dynamicAnimator = [[UIDynamicAnimator alloc] initWithCollectionViewLayout:self]; CGSize contentSize = [self collectionViewContentSize]; CGRect contentRect = { CGPointZero, contentSize }; ! NSArray *layoutAttributes = [super layoutAttributesForElementsInRect:contentRect]; // create spring behavior for each item for (UICollectionViewLayoutAttributes *attribute in layoutAttributes) { ! } ! // ! UIAttachmentBehavior *springBehavior; springBehavior = [[UIAttachmentBehavior alloc] initWithItem:attribute attachedToAnchor:[attribute center]]; springBehavior.length = 0.0; springBehavior.damping = 0.5; springBehavior.frequency = 0.8; } } [self.dynamicAnimator addBehavior:springBehavior]; ... continue @end
  • Example: collection view @implementation DPProportionalSpringFlowLayout ! // ! ... continue from previous slide - (void)prepareLayout { [super prepareLayout]; ! ! ! if (nil == [self dynamicAnimator]) { self.dynamicAnimator = [[UIDynamicAnimator alloc] initWithCollectionViewLayout:self]; CGSize contentSize = [self collectionViewContentSize]; CGRect contentRect = { CGPointZero, contentSize }; ! NSArray *layoutAttributes = [super layoutAttributesForElementsInRect:contentRect]; // create spring behavior for each item for (UICollectionViewLayoutAttributes *attribute in layoutAttributes) { ! } ! // ! UIAttachmentBehavior *springBehavior; springBehavior = [[UIAttachmentBehavior alloc] initWithItem:attribute attachedToAnchor:[attribute center]]; springBehavior.length = 0.0; springBehavior.damping = 0.5; springBehavior.frequency = 0.8; } } [self.dynamicAnimator addBehavior:springBehavior]; ... continue @end
  • Example: collection view @implementation DPProportionalSpringFlowLayout ! // ! ... continue from previous slide - (void)prepareLayout { [super prepareLayout]; ! ! ! if (nil == [self dynamicAnimator]) { self.dynamicAnimator = [[UIDynamicAnimator alloc] initWithCollectionViewLayout:self]; CGSize contentSize = [self collectionViewContentSize]; CGRect contentRect = { CGPointZero, contentSize }; ! NSArray *layoutAttributes = [super layoutAttributesForElementsInRect:contentRect]; // create spring behavior for each item for (UICollectionViewLayoutAttributes *attribute in layoutAttributes) { ! } ! // ! UIAttachmentBehavior *springBehavior; springBehavior = [[UIAttachmentBehavior alloc] initWithItem:attribute attachedToAnchor:[attribute center]]; springBehavior.length = 0.0; springBehavior.damping = 0.5; springBehavior.frequency = 0.8; } } [self.dynamicAnimator addBehavior:springBehavior]; ... continue @end
  • Example: collection view @implementation DPProportionalSpringFlowLayout // ... continue form previous slide ! - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { UIScrollView *scrollView = [self collectionView]; CGFloat scrollDelta = newBounds.origin.y - scrollView.bounds.origin.y; CGPoint touchLocation = [scrollView.panGestureRecognizer locationInView:scrollView]; for (UIAttachmentBehavior *springBehavior in [self.dynamicAnimator behaviors]) { CGPoint anchorPoint = [springBehavior anchorPoint]; CGFloat distanceFromTouch = fabsf(touchLocation.y - anchorPoint.y); CGFloat scrollResistance = distanceFromTouch / 500.0f; ! UICollectionViewLayoutAttributes *attribute = [springBehavior.items firstObject]; CGPoint center = [attribute center]; CGFloat springStretch = scrollDelta * scrollResistance; if (scroll > 0) { center.y += MIN(scrollDelta, scrollDelta * springStretch); } else { center.y += MAX(scrollDelta, scrollDelta * springStretch); } ! attribute.center = center; [self.dynamicAnimator updateItemUsingCurrentState:attribute]; } return NO; } @end
  • Example: collection view @implementation DPProportionalSpringFlowLayout // ... continue form previous slide ! - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { UIScrollView *scrollView = [self collectionView]; CGFloat scrollDelta = newBounds.origin.y - scrollView.bounds.origin.y; CGPoint touchLocation = [scrollView.panGestureRecognizer locationInView:scrollView]; for (UIAttachmentBehavior *springBehavior in [self.dynamicAnimator behaviors]) { CGPoint anchorPoint = [springBehavior anchorPoint]; CGFloat distanceFromTouch = fabsf(touchLocation.y - anchorPoint.y); CGFloat scrollResistance = distanceFromTouch / 500.0f; ! UICollectionViewLayoutAttributes *attribute = [springBehavior.items firstObject]; CGPoint center = [attribute center]; CGFloat springStretch = scrollDelta * scrollResistance; if (scroll > 0) { center.y += MIN(scrollDelta, scrollDelta * springStretch); } else { center.y += MAX(scrollDelta, scrollDelta * springStretch); } ! attribute.center = center; [self.dynamicAnimator updateItemUsingCurrentState:attribute]; } return NO; } @end
  • Example: collection view @implementation DPProportionalSpringFlowLayout // ... continue form previous slide ! - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { UIScrollView *scrollView = [self collectionView]; CGFloat scrollDelta = newBounds.origin.y - scrollView.bounds.origin.y; CGPoint touchLocation = [scrollView.panGestureRecognizer locationInView:scrollView]; for (UIAttachmentBehavior *springBehavior in [self.dynamicAnimator behaviors]) { CGPoint anchorPoint = [springBehavior anchorPoint]; CGFloat distanceFromTouch = fabsf(touchLocation.y - anchorPoint.y); CGFloat scrollResistance = distanceFromTouch / 500.0f; ! UICollectionViewLayoutAttributes *attribute = [springBehavior.items firstObject]; CGPoint center = [attribute center]; CGFloat springStretch = scrollDelta * scrollResistance; if (scroll > 0) { center.y += MIN(scrollDelta, scrollDelta * springStretch); } else { center.y += MAX(scrollDelta, scrollDelta * springStretch); } ! attribute.center = center; [self.dynamicAnimator updateItemUsingCurrentState:attribute]; } return NO; } @end
  • Example: collection view @implementation DPProportionalSpringFlowLayout // ... continue form previous slide ! - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { UIScrollView *scrollView = [self collectionView]; CGFloat scrollDelta = newBounds.origin.y - scrollView.bounds.origin.y; CGPoint touchLocation = [scrollView.panGestureRecognizer locationInView:scrollView]; for (UIAttachmentBehavior *springBehavior in [self.dynamicAnimator behaviors]) { CGPoint anchorPoint = [springBehavior anchorPoint]; CGFloat distanceFromTouch = fabsf(touchLocation.y - anchorPoint.y); CGFloat scrollResistance = distanceFromTouch / 500.0f; ! UICollectionViewLayoutAttributes *attribute = [springBehavior.items firstObject]; CGPoint center = [attribute center]; CGFloat springStretch = scrollDelta * scrollResistance; if (scroll > 0) { center.y += MIN(scrollDelta, scrollDelta * springStretch); } else { center.y += MAX(scrollDelta, scrollDelta * springStretch); } ! attribute.center = center; [self.dynamicAnimator updateItemUsingCurrentState:attribute]; } return NO; } @end
  • Example: collection view @implementation DPProportionalSpringFlowLayout // ... continue form previous slide ! - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { UIScrollView *scrollView = [self collectionView]; CGFloat scrollDelta = newBounds.origin.y - scrollView.bounds.origin.y; CGPoint touchLocation = [scrollView.panGestureRecognizer locationInView:scrollView]; for (UIAttachmentBehavior *springBehavior in [self.dynamicAnimator behaviors]) { CGPoint anchorPoint = [springBehavior anchorPoint]; CGFloat distanceFromTouch = fabsf(touchLocation.y - anchorPoint.y); CGFloat scrollResistance = distanceFromTouch / 500.0f; ! UICollectionViewLayoutAttributes *attribute = [springBehavior.items firstObject]; CGPoint center = [attribute center]; CGFloat springStretch = scrollDelta * scrollResistance; if (scroll > 0) { center.y += MIN(scrollDelta, scrollDelta * springStretch); } else { center.y += MAX(scrollDelta, scrollDelta * springStretch); } ! attribute.center = center; [self.dynamicAnimator updateItemUsingCurrentState:attribute]; } return NO; } @end
  • Example: collection view @implementation DPProportionalSpringFlowLayout // ... continue form previous slide ! - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { UIScrollView *scrollView = [self collectionView]; CGFloat scrollDelta = newBounds.origin.y - scrollView.bounds.origin.y; CGPoint touchLocation = [scrollView.panGestureRecognizer locationInView:scrollView]; for (UIAttachmentBehavior *springBehavior in [self.dynamicAnimator behaviors]) { CGPoint anchorPoint = [springBehavior anchorPoint]; CGFloat distanceFromTouch = fabsf(touchLocation.y - anchorPoint.y); CGFloat scrollResistance = distanceFromTouch / 500.0f; ! UICollectionViewLayoutAttributes *attribute = [springBehavior.items firstObject]; CGPoint center = [attribute center]; CGFloat springStretch = scrollDelta * scrollResistance; if (scroll > 0) { center.y += MIN(scrollDelta, scrollDelta * springStretch); } else { center.y += MAX(scrollDelta, scrollDelta * springStretch); } ! attribute.center = center; [self.dynamicAnimator updateItemUsingCurrentState:attribute]; } return NO; } @end
  • Example: collection view @implementation DPProportionalSpringFlowLayout // ... continue form previous slide ! - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { UIScrollView *scrollView = [self collectionView]; CGFloat scrollDelta = newBounds.origin.y - scrollView.bounds.origin.y; CGPoint touchLocation = [scrollView.panGestureRecognizer locationInView:scrollView]; for (UIAttachmentBehavior *springBehavior in [self.dynamicAnimator behaviors]) { CGPoint anchorPoint = [springBehavior anchorPoint]; CGFloat distanceFromTouch = fabsf(touchLocation.y - anchorPoint.y); CGFloat scrollResistance = distanceFromTouch / 500.0f; ! UICollectionViewLayoutAttributes *attribute = [springBehavior.items firstObject]; CGPoint center = [attribute center]; CGFloat springStretch = scrollDelta * scrollResistance; if (scroll > 0) { center.y += MIN(scrollDelta, scrollDelta * springStretch); } else { center.y += MAX(scrollDelta, scrollDelta * springStretch); } ! attribute.center = center; [self.dynamicAnimator updateItemUsingCurrentState:attribute]; } return NO; } @end
  • Example: collection view @implementation DPProportionalSpringFlowLayout // ... continue form previous slide ! - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { UIScrollView *scrollView = [self collectionView]; CGFloat scrollDelta = newBounds.origin.y - scrollView.bounds.origin.y; CGPoint touchLocation = [scrollView.panGestureRecognizer locationInView:scrollView]; for (UIAttachmentBehavior *springBehavior in [self.dynamicAnimator behaviors]) { CGPoint anchorPoint = [springBehavior anchorPoint]; CGFloat distanceFromTouch = fabsf(touchLocation.y - anchorPoint.y); CGFloat scrollResistance = distanceFromTouch / 500.0f; ! UICollectionViewLayoutAttributes *attribute = [springBehavior.items firstObject]; CGPoint center = [attribute center]; CGFloat springStretch = scrollDelta * scrollResistance; if (scroll > 0) { center.y += MIN(scrollDelta, scrollDelta * springStretch); } else { center.y += MAX(scrollDelta, scrollDelta * springStretch); } ! attribute.center = center; [self.dynamicAnimator updateItemUsingCurrentState:attribute]; } return NO; } @end
  • Example: collection view @implementation DPProportionalSpringFlowLayout // ... continue form previous slide ! - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { UIScrollView *scrollView = [self collectionView]; CGFloat scrollDelta = newBounds.origin.y - scrollView.bounds.origin.y; CGPoint touchLocation = [scrollView.panGestureRecognizer locationInView:scrollView]; for (UIAttachmentBehavior *springBehavior in [self.dynamicAnimator behaviors]) { CGPoint anchorPoint = [springBehavior anchorPoint]; CGFloat distanceFromTouch = fabsf(touchLocation.y - anchorPoint.y); CGFloat scrollResistance = distanceFromTouch / 500.0f; ! UICollectionViewLayoutAttributes *attribute = [springBehavior.items firstObject]; CGPoint center = [attribute center]; CGFloat springStretch = scrollDelta * scrollResistance; if (scroll > 0) { center.y += MIN(scrollDelta, scrollDelta * springStretch); } else { center.y += MAX(scrollDelta, scrollDelta * springStretch); } ! attribute.center = center; [self.dynamicAnimator updateItemUsingCurrentState:attribute]; } return NO; } @end
  • Example: collection view @implementation DPProportionalSpringFlowLayout // ... continue form previous slide ! - (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { UIScrollView *scrollView = [self collectionView]; CGFloat scrollDelta = newBounds.origin.y - scrollView.bounds.origin.y; CGPoint touchLocation = [scrollView.panGestureRecognizer locationInView:scrollView]; for (UIAttachmentBehavior *springBehavior in [self.dynamicAnimator behaviors]) { CGPoint anchorPoint = [springBehavior anchorPoint]; CGFloat distanceFromTouch = fabsf(touchLocation.y - anchorPoint.y); CGFloat scrollResistance = distanceFromTouch / 500.0f; ! UICollectionViewLayoutAttributes *attribute = [springBehavior.items firstObject]; CGPoint center = [attribute center]; CGFloat springStretch = scrollDelta * scrollResistance; if (scroll > 0) { center.y += MIN(scrollDelta, scrollDelta * springStretch); } else { center.y += MAX(scrollDelta, scrollDelta * springStretch); } ! attribute.center = center; [self.dynamicAnimator updateItemUsingCurrentState:attribute]; } return NO; } @end
  • Example: collection view @import UIKit; ! @interface DPDynamicCollectionViewViewController : UIViewController @end ! ! ! ! ! const NSInteger kCellCount = 20; ! @interface DPDynamicCollectionViewViewController() <UICollectionViewDataSource, UICollectionViewDelegate> ! ! ! ! @property (weak, nonatomic) IBOutlet UICollectionView *collectionView; @property (strong, nonatomic) UICollectionViewFlowLayout *flowLayout; @property (strong, nonatomic) NSMutableArray *colors; @end ! !
  • Example: collection view @import UIKit; ! @interface DPDynamicCollectionViewViewController : UIViewController @end ! ! ! ! ! const NSInteger kCellCount = 20; ! @interface DPDynamicCollectionViewViewController() <UICollectionViewDataSource, UICollectionViewDelegate> ! ! ! ! @property (weak, nonatomic) IBOutlet UICollectionView *collectionView; @property (strong, nonatomic) UICollectionViewFlowLayout *flowLayout; @property (strong, nonatomic) NSMutableArray *colors; @end ! !
  • Example: collection view @import UIKit; ! @interface DPDynamicCollectionViewViewController : UIViewController @end ! ! ! ! ! const NSInteger kCellCount = 20; ! @interface DPDynamicCollectionViewViewController() <UICollectionViewDataSource, UICollectionViewDelegate> ! ! ! ! @property (weak, nonatomic) IBOutlet UICollectionView *collectionView; @property (strong, nonatomic) UICollectionViewFlowLayout *flowLayout; @property (strong, nonatomic) NSMutableArray *colors; @end ! !
  • Example: collection view @implementation DPDynamicCollectionViewViewController ! ... ! - (void)viewDidLoad { [super viewDidLoad]; ! ! self.colors = [self cellColors]; [self.collectionView registerClass:[DPCollectionViewCell class] forCellWithReuseIdentifier:[DPCollectionViewCell cellIdentifier]]; self.flowLayout = [[DPProportionalSpringFlowLayout alloc] init]; ! [self.collectionView setCollectionViewLayout:[self flowLayout]]; } ! // ... continue ! ! ! ! @end
  • Example: collection view @implementation DPDynamicCollectionViewViewController ! ... ! - (void)viewDidLoad { [super viewDidLoad]; ! ! self.colors = [self cellColors]; [self.collectionView registerClass:[DPCollectionViewCell class] forCellWithReuseIdentifier:[DPCollectionViewCell cellIdentifier]]; self.flowLayout = [[DPProportionalSpringFlowLayout alloc] init]; ! [self.collectionView setCollectionViewLayout:[self flowLayout]]; } ! // ... continue ! ! ! ! @end
  • Example: collection view @implementation DPDynamicCollectionViewViewController ! ... ! - (void)viewDidLoad { [super viewDidLoad]; ! ! self.colors = [self cellColors]; [self.collectionView registerClass:[DPCollectionViewCell class] forCellWithReuseIdentifier:[DPCollectionViewCell cellIdentifier]]; self.flowLayout = [[DPProportionalSpringFlowLayout alloc] init]; ! [self.collectionView setCollectionViewLayout:[self flowLayout]]; } ! // ... continue ! ! ! ! @end
  • Example: collection view @implementation DPDynamicCollectionViewViewController ! // ... continue form previous slide ! ! - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return kCellCount; } ! - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { ! ! DPCollectionViewCell *cell; cell = (DPCollectionViewCell *) [collectionView dequeueReusableCellWithReuseIdentifier: [DPCollectionViewCell cellIdentifier] forIndexPath:indexPath]; [self configureCell:cell forItemAtIndexPath:indexPath]; return cell; } ! @end
  • Example: collection view @implementation DPDynamicCollectionViewViewController ! // ... continue form previous slide ! ! - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return kCellCount; } ! - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { ! ! DPCollectionViewCell *cell; cell = (DPCollectionViewCell *) [collectionView dequeueReusableCellWithReuseIdentifier: [DPCollectionViewCell cellIdentifier] forIndexPath:indexPath]; [self configureCell:cell forItemAtIndexPath:indexPath]; return cell; } ! @end
  • Example: collection view @implementation DPDynamicCollectionViewViewController ! // ... continue form previous slide ! ! - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return kCellCount; } ! - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { ! ! DPCollectionViewCell *cell; cell = (DPCollectionViewCell *) [collectionView dequeueReusableCellWithReuseIdentifier: [DPCollectionViewCell cellIdentifier] forIndexPath:indexPath]; [self configureCell:cell forItemAtIndexPath:indexPath]; return cell; } ! @end
  • Conclusion
  • Tips • Build iteratively
  • Tips • Build iteratively • Check for setup which don’t have solutions
  • Tips • Build iteratively • Check for setup which don’t have solutions
  • Tips • Build iteratively • Check for setup which don’t have solutions
  • Tips • Build iteratively • Check for setup which don’t have solutions • Collision only for rectangle objects
  • Tips • Build iteratively • Check for setup which don’t have solutions • Collision only for rectangle objects
  • Tips • Build iteratively • Check for setup which don’t have solutions • Collision only for rectangle objects • Not an physics-accurate simulation tool
  • Tips • Build iteratively • Check for setup which don’t have solutions • Collision only for rectangle objects • Not an physics-accurate simulation tool • Not for games
  • Tips • Build iteratively • Check for setup which don’t have solutions • Collision only for rectangle objects • Not an physics-accurate simulation tool • Not for games • use Sprite Kit
  • Tips • Build iteratively • Check for setup which don’t have solutions • Collision only for rectangle objects • Not an physics-accurate simulation tool • Not for games • use Sprite Kit • Focus on the user experience
  • Animations and Interactions • Can combine all previous techniques
  • Animations and Interactions • Can combine all previous techniques • Core Animation
  • Animations and Interactions • Can combine all previous techniques • Core Animation • UIView animations +(void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay usingSpringWithDamping:(CGFloat)dampingRatio initialSpringVelocity:(CGFloat)velocity options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion;
  • Animations and Interactions • Can combine all previous techniques • Core Animation • UIView animations +(void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay usingSpringWithDamping:(CGFloat)dampingRatio initialSpringVelocity:(CGFloat)velocity options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion; • Motion effects
  • Animations and Interactions • Can combine all previous techniques • Core Animation • UIView animations +(void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay usingSpringWithDamping:(CGFloat)dampingRatio initialSpringVelocity:(CGFloat)velocity options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion; • Motion effects • Gestures
  • Endings "With great power comes great responsibility." Francois-Marie Arouet a.k.a. Voltaire
  • References • Apple documentation • WWDC 2013 sessions 206 Getting Started with UIKit Dynamics 221 Advanced Techniques with UIKit Dynamics 217 Exploring Scroll Views in iOS 7 218 Custom Transitions Using View Controllers 226 Implementing Engaging UI on iOS
  • References • 3rd party docs iOS 7 by tutorials Chap. 2 (by raywenderlich.com) Objc.io issue #5 • Example code DynamicPlayground UIKit Dynamics Catalog (iOS Dev Library Sample Code)
  • Q&A
  • … and one more thing
  • It’s beer O’Clock
  • THANKS