SlideShare a Scribd company logo
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
Hackatron - UIKit Dynamics
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”
Hackatron - UIKit Dynamics
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
Hackatron - UIKit Dynamics
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
Hackatron - UIKit Dynamics
… and one more thing
It’s beer O’Clock
THANKS

More Related Content

Similar to Hackatron - UIKit Dynamics (20)

PDF
#pragma conf 2013 - UIKit dynamics
Renzo G. Pretto
 
PPTX
Ui kit dynamics(1)
geniteamsolutions
 
PDF
iOS UIkit Dynamic
Seta Cheam
 
PDF
UI Dynamics
SV.CO
 
PDF
UIKit Dynamics
Craig VanderZwaag
 
PPTX
iOS for C# Developers - DevConnections Talk
Miguel de Icaza
 
PDF
Application Kit Framework Reference Appkitobjc Apple Computer
mugmanwening
 
PPT
Programming iOS in C#
Frank Krueger
 
PPTX
Ios development 2
elnaqah
 
PPTX
Xamarin.Mac Introduction
Miguel de Icaza
 
PDF
UIKit Dynamics
Robert Brown
 
PDF
FI MUNI 2012 - iOS Basics
Petr Dvorak
 
PPTX
Building your first iOS app using Xamarin
Gill Cleeren
 
PDF
iOS 7 Programming Cookbook 2nd Edition Vandad Nahavandipoor
gancezatta3e
 
PDF
iOS 7 Programming Cookbook 2nd Edition Vandad Nahavandipoor
gancezatta3e
 
KEY
Animation in iOS
Alexis Goldstein
 
PDF
Ios 7 Programming Cookbook 2nd Edition Vandad Nahavandipoor
qgxviia0040
 
PDF
MFF UK - Introduction to iOS
Petr Dvorak
 
PDF
Introduction of Xcode
Dhaval Kaneria
 
PPTX
iOS Beginners Lesson 2
Calvin Cheng
 
#pragma conf 2013 - UIKit dynamics
Renzo G. Pretto
 
Ui kit dynamics(1)
geniteamsolutions
 
iOS UIkit Dynamic
Seta Cheam
 
UI Dynamics
SV.CO
 
UIKit Dynamics
Craig VanderZwaag
 
iOS for C# Developers - DevConnections Talk
Miguel de Icaza
 
Application Kit Framework Reference Appkitobjc Apple Computer
mugmanwening
 
Programming iOS in C#
Frank Krueger
 
Ios development 2
elnaqah
 
Xamarin.Mac Introduction
Miguel de Icaza
 
UIKit Dynamics
Robert Brown
 
FI MUNI 2012 - iOS Basics
Petr Dvorak
 
Building your first iOS app using Xamarin
Gill Cleeren
 
iOS 7 Programming Cookbook 2nd Edition Vandad Nahavandipoor
gancezatta3e
 
iOS 7 Programming Cookbook 2nd Edition Vandad Nahavandipoor
gancezatta3e
 
Animation in iOS
Alexis Goldstein
 
Ios 7 Programming Cookbook 2nd Edition Vandad Nahavandipoor
qgxviia0040
 
MFF UK - Introduction to iOS
Petr Dvorak
 
Introduction of Xcode
Dhaval Kaneria
 
iOS Beginners Lesson 2
Calvin Cheng
 

Recently uploaded (20)

PPTX
Extensions Framework (XaaS) - Enabling Orchestrate Anything
ShapeBlue
 
PDF
SFWelly Summer 25 Release Highlights July 2025
Anna Loughnan Colquhoun
 
PDF
NewMind AI - Journal 100 Insights After The 100th Issue
NewMind AI
 
PDF
How Startups Are Growing Faster with App Developers in Australia.pdf
India App Developer
 
PDF
Apache CloudStack 201: Let's Design & Build an IaaS Cloud
ShapeBlue
 
PDF
Français Patch Tuesday - Juillet
Ivanti
 
PPTX
Darren Mills The Migration Modernization Balancing Act: Navigating Risks and...
AWS Chicago
 
PDF
LLMs.txt: Easily Control How AI Crawls Your Site
Keploy
 
PDF
SWEBOK Guide and Software Services Engineering Education
Hironori Washizaki
 
PDF
CIFDAQ Weekly Market Wrap for 11th July 2025
CIFDAQ
 
PDF
Rethinking Security Operations - SOC Evolution Journey.pdf
Haris Chughtai
 
PDF
Complete JavaScript Notes: From Basics to Advanced Concepts.pdf
haydendavispro
 
PPTX
Building Search Using OpenSearch: Limitations and Workarounds
Sease
 
PDF
Why Orbit Edge Tech is a Top Next JS Development Company in 2025
mahendraalaska08
 
PDF
Persuasive AI: risks and opportunities in the age of digital debate
Speck&Tech
 
PDF
Building Resilience with Digital Twins : Lessons from Korea
SANGHEE SHIN
 
PPTX
✨Unleashing Collaboration: Salesforce Channels & Community Power in Patna!✨
SanjeetMishra29
 
PDF
TrustArc Webinar - Data Privacy Trends 2025: Mid-Year Insights & Program Stra...
TrustArc
 
PDF
NewMind AI Journal - Weekly Chronicles - July'25 Week II
NewMind AI
 
PPTX
WooCommerce Workshop: Bring Your Laptop
Laura Hartwig
 
Extensions Framework (XaaS) - Enabling Orchestrate Anything
ShapeBlue
 
SFWelly Summer 25 Release Highlights July 2025
Anna Loughnan Colquhoun
 
NewMind AI - Journal 100 Insights After The 100th Issue
NewMind AI
 
How Startups Are Growing Faster with App Developers in Australia.pdf
India App Developer
 
Apache CloudStack 201: Let's Design & Build an IaaS Cloud
ShapeBlue
 
Français Patch Tuesday - Juillet
Ivanti
 
Darren Mills The Migration Modernization Balancing Act: Navigating Risks and...
AWS Chicago
 
LLMs.txt: Easily Control How AI Crawls Your Site
Keploy
 
SWEBOK Guide and Software Services Engineering Education
Hironori Washizaki
 
CIFDAQ Weekly Market Wrap for 11th July 2025
CIFDAQ
 
Rethinking Security Operations - SOC Evolution Journey.pdf
Haris Chughtai
 
Complete JavaScript Notes: From Basics to Advanced Concepts.pdf
haydendavispro
 
Building Search Using OpenSearch: Limitations and Workarounds
Sease
 
Why Orbit Edge Tech is a Top Next JS Development Company in 2025
mahendraalaska08
 
Persuasive AI: risks and opportunities in the age of digital debate
Speck&Tech
 
Building Resilience with Digital Twins : Lessons from Korea
SANGHEE SHIN
 
✨Unleashing Collaboration: Salesforce Channels & Community Power in Patna!✨
SanjeetMishra29
 
TrustArc Webinar - Data Privacy Trends 2025: Mid-Year Insights & Program Stra...
TrustArc
 
NewMind AI Journal - Weekly Chronicles - July'25 Week II
NewMind AI
 
WooCommerce Workshop: Bring Your Laptop
Laura Hartwig
 

Hackatron - UIKit Dynamics

  • 1. UIKit Dynamics Let the physics flow Renzo G. Pretto iOS Developer
  • 4. About me Renzo iOS Developer H-art ! #pragma mark founder [email protected] ! @rgpretto
  • 6. Chi siamo programmatori e imprenditori, ma soprattutto appassionati
  • 7. Cosa creare una community di sviluppatori iOS e OS X
  • 8. Perché sentivamo l’esigenza di condividere e confrontarci
  • 9. Dove nel mondo virtuale, ma soprattutto nel mondo reale
  • 10. Come attraverso incontri periodici, eventi formativi e conferenze
  • 11. Associazione dal Settembre siamo ufficialmente un’associazione culturale
  • 12. Associazione dal Settembre siamo ufficialmente un’associazione culturale Marco Paolo Matteo Renzo Francesco Massimo Stefano Giuseppe
  • 14. 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”
  • 16. 152 partecipanti 16 speaker 15 sponsor 8 organizzatori
  • 17. 16 sessioni tecniche 10 ore di conferenza 2 track tematiche 20 gadget, licenze e coupon
  • 19. Ottobre 2013 la comunità è cresciuta molto, oggi siamo in 150
  • 20. Partecipanti più di 300 persone hanno seguito i nostri eventi
  • 21. Social 205 iscritti al gruppo su facebook e 122 follower su twitter
  • 23. Dove Brescia, Bergamo,Verona,Venezia, Milano 
 e presto a Treviso e Roma
  • 24. follow us @pragmamarkorg join to fb.com/groups/pragmamark/ subscribe on pragmamark.org
  • 26. Today Agenda • Introduction and core concepts
  • 27. Today Agenda • Introduction and core concepts • Standard effects: dynamic behaviors
  • 28. Today Agenda • Introduction and core concepts • Standard effects: dynamic behaviors • Custom effects: custom behaviors
  • 29. Today Agenda • Introduction and core concepts • Standard effects: dynamic behaviors • Custom effects: custom behaviors • Advanced concepts
  • 30. Today Agenda • Introduction and core concepts • Standard effects: dynamic behaviors • Custom effects: custom behaviors • Advanced concepts • UIDynamicItem
  • 31. Today Agenda • Introduction and core concepts • Standard effects: dynamic behaviors • Custom effects: custom behaviors • Advanced concepts • UIDynamicItem • Collection View
  • 32. Today Agenda • Introduction and core concepts • Standard effects: dynamic behaviors • Custom effects: custom behaviors • Advanced concepts • UIDynamicItem • Collection View • Conclusion
  • 45. UIDynamicAnimator • Define the coordinate system UIDynamicAnimator Reference view
  • 46. UIDynamicAnimator • Define the coordinate system • Wraps underline engine UIDynamicAnimator Reference view
  • 47. UIDynamicAnimator • Define the coordinate system • Wraps underline engine • Keeps track of all the associated behaviors UIDynamicAnimator Reference view
  • 48. UIDynamicAnimator • Define the coordinate system • Wraps underline engine • Keeps track of all the associated behaviors • Run and optimize the animation UIDynamicAnimator Reference view
  • 49. 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
  • 50. 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]; ...
  • 51. 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]; ...
  • 52. 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]; ...
  • 53. 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]; ...
  • 54. UIDynamicAnimatorDelegate @protocol UIDynamicAnimatorDelegate <NSObject> ! @optional - (void)dynamicAnimatorWillResume:(UIDynamicAnimator*)animator; - (void)dynamicAnimatorDidPause:(UIDynamicAnimator*)animator; ! @end
  • 55. UIDynamicAnimatorDelegate @protocol UIDynamicAnimatorDelegate <NSObject> ! @optional - (void)dynamicAnimatorWillResume:(UIDynamicAnimator*)animator; - (void)dynamicAnimatorDidPause:(UIDynamicAnimator*)animator; ! @end • Notify pausing and resuming of UIKit Dynamic animator
  • 58. UIDynamicBehaviour UIDynamicAnimator UIDynamicBehavior • Associated to UIDynamicAnimator • Add and remove behaviours to an animator at any times
  • 59. 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
  • 60. 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
  • 61. 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
  • 62. Behaviors Common characteristics • Initialised with items to animate
  • 63. Behaviors Common characteristics • Initialised with items to animate • Items can be added to behavior at any times
  • 64. 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
  • 65. 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
  • 69. Default Behaviors UIDynamicBehavior • Gravity • Collisions UIGravityBehavior UICollisionBehavior
  • 70. Default Behaviors UIDynamicBehavior • Gravity • Collisions • Attachments UIGravityBehavior UICollisionBehavior UIAttachmentBehavior
  • 71. Default Behaviors UIDynamicBehavior • Gravity • Collisions • Attachments • Snap UIGravityBehavior UICollisionBehavior UIAttachmentBehavior UISnapBehavior
  • 72. Default Behaviors UIDynamicBehavior • Gravity • Collisions • Attachments UIGravityBehavior UICollisionBehavior UIAttachmentBehavior • Snap UISnapBehavior • Forces UIPushBehavior
  • 73. Default Behaviors UIDynamicBehavior • Gravity • Collisions • Attachments UIGravityBehavior UICollisionBehavior UIAttachmentBehavior • Snap UISnapBehavior • Forces UIPushBehavior • Item properties UIDynamicItemBehavior
  • 77. 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
  • 78. 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
  • 79. 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
  • 80. 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
  • 81. 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
  • 82. UIGravityBehavior • Defined by a gravity vector @property (readwrite, nonatomic) CGVector gravityDirection;
  • 83. UIGravityBehavior • Defined by a gravity vector @property (readwrite, nonatomic) CGVector gravityDirection; or @property (readwrite, nonatomic) CGFloat angle; @property (readwrite, nonatomic) CGFloat magnitude;
  • 84. 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)
  • 85. 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)
  • 86. 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)
  • 89. 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];
  • 90. 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];
  • 91. 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];
  • 92. 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];
  • 93. 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];
  • 94. 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];
  • 95. 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];
  • 96. Collision Boundaries • Can specify different boundaries
  • 97. Collision Boundaries • Can specify different boundaries • Reference view @property (nonatomic, readwrite) BOOL translatesReferenceBoundsIntoBoundary;
  • 98. Collision Boundaries • Can specify different boundaries • Reference view @property (nonatomic, readwrite) BOOL translatesReferenceBoundsIntoBoundary; • Insets to reference view - (void)setTranslatesReferenceBoundsIntoBoundaryWithInsets:(UIEdgeInsets)insets;
  • 99. 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;
  • 100. 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;
  • 101. 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;
  • 102. 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
  • 103. Collision Mode • Property collisionmode
  • 104. Collision Mode • Property collisionmode @property (nonatomic, readwrite) UICollisionBehaviorMode collisionMode;
  • 105. Collision Mode • Property collisionmode @property (nonatomic, readwrite) UICollisionBehaviorMode collisionMode; • UICollisionBehaviorModeBoundaries
  • 106. Collision Mode • Property collisionmode @property (nonatomic, readwrite) UICollisionBehaviorMode collisionMode; • UICollisionBehaviorModeBoundaries • UICollisionBehaviorModeItems
  • 107. Collision Mode • Property collisionmode @property (nonatomic, readwrite) UICollisionBehaviorMode collisionMode; • UICollisionBehaviorModeBoundaries • UICollisionBehaviorModeItems • UICollisionBehaviorModeEverything (default)
  • 108. Tips • Can use multiple collision behaviors
  • 109. Tips • Can use multiple collision behaviors • Add and remove items to this behaviour anytime - (void)addItem:(id <UIDynamicItem>)item; - (void)removeItem:(id <UIDynamicItem>)item;
  • 110. 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
  • 111. UICollisionBehaviorDelegate • Methods that inform collision start / end between view
  • 112. 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;
  • 113. 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
  • 114. 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;
  • 115. 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;
  • 116. 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
  • 119. 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
  • 120. 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
  • 121. 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
  • 122. 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
  • 123. 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
  • 124. 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
  • 125. UIAttachmentBehavior • View connected to an attachment point
  • 126. UIAttachmentBehavior • View connected to an attachment point - (instancetype)initWithItem:(id <UIDynamicItem>)item attachedToAnchor:(CGPoint)point;
  • 127. UIAttachmentBehavior • View connected to an attachment point - (instancetype)initWithItem:(id <UIDynamicItem>)item attachedToAnchor:(CGPoint)point; • Two views connected together
  • 128. 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;
  • 129. 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
  • 130. 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;
  • 131. 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;
  • 133. Springs • Springs @property (readwrite, nonatomic) CGFloat damping;
  • 134. Springs • Springs @property (readwrite, nonatomic) CGFloat damping; @property (readwrite, nonatomic) CGFloat frequency;
  • 135. Springs • Springs @property (readwrite, nonatomic) CGFloat damping; @property (readwrite, nonatomic) CGFloat frequency;
  • 138. 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
  • 139. 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
  • 140. 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
  • 141. 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
  • 142. 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
  • 143. 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
  • 144. UISnapBehavior • Snap view in place in non rotated state
  • 145. UISnapBehavior • Snap view in place in non rotated state - (instancetype)initWithItem:(id <UIDynamicItem>)item snapToPoint:(CGPoint)point;
  • 146. UISnapBehavior • Snap view in place in non rotated state - (instancetype)initWithItem:(id <UIDynamicItem>)item snapToPoint:(CGPoint)point; • Customize the dumping effects
  • 147. 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;
  • 150. UIPushBehavior ~ F = m ~ , apply force to views: a •
  • 151. UIPushBehavior ~ F = m ~ , apply force to views: a • - (instancetype)initWithItems:(NSArray *)items mode:(UIPushBehaviorMode)mode;
  • 152. UIPushBehavior ~ F = m ~ , apply force to views: a • - (instancetype)initWithItems:(NSArray *)items mode:(UIPushBehaviorMode)mode; • Force vector expressed in two way:
  • 153. 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;
  • 154. 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;
  • 156. UIPushBehavior • Customize where apply this force in the view
  • 157. UIPushBehavior • Customize where apply this force in the view
  • 158. UIPushBehavior • Customize where apply this force in the view - (void)setTargetOffsetFromCenter:(UIOffset)o forItem:(id <UIDynamicItem>)item;
  • 159. UIPushBehavior • Customize where apply this force in the view - (void)setTargetOffsetFromCenter:(UIOffset)o forItem:(id <UIDynamicItem>)item;
  • 160. 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
  • 161. 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;
  • 162. 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;
  • 163. 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;
  • 164. UIPushBehavior Mode • Different mode to apply forces: - (instancetype)initWithItems:(NSArray *)items mode:(UIPushBehaviorMode)mode;
  • 165. UIPushBehavior Mode • Different mode to apply forces: - (instancetype)initWithItems:(NSArray *)items mode:(UIPushBehaviorMode)mode; • UIPushBehaviorModeContinuous
  • 166. UIPushBehavior Mode • Different mode to apply forces: - (instancetype)initWithItems:(NSArray *)items mode:(UIPushBehaviorMode)mode; • UIPushBehaviorModeContinuous • force still be applied while behaviour is active
  • 167. 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
  • 168. 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
  • 169. 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
  • 170. 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)
  • 171. 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
  • 172. 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;
  • 173. Example: force comparison ~ F =m~ a ~ F ~= a m
  • 174. Example: force comparison ~ F =m~ a ~ F ~= a m
  • 178. Feel The Force! • Gravity • views accelerate with the same rate
  • 179. Feel The Force! • Gravity • views accelerate with the same rate • Push behavior in continuos mode
  • 180. Feel The Force! • Gravity • views accelerate with the same rate • Push behavior in continuos mode • the smaller views accelerate more
  • 181. 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
  • 182. 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
  • 183. 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
  • 184. Unit of Measure • Real world: Newton
  • 185. Unit of Measure • Real world: Newton 1 Newton accelerate 1Kg at a rate of 1 m/s2 •
  • 186. 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
  • 187. 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”
  • 190. UIDynamicItemBehavior • Customize dynamics properties for items @property (readwrite, nonatomic) CGFloat elasticity;
  • 191. UIDynamicItemBehavior • Customize dynamics properties for items @property (readwrite, nonatomic) CGFloat elasticity; @property (readwrite, nonatomic) CGFloat friction;
  • 192. UIDynamicItemBehavior • Customize dynamics properties for items @property (readwrite, nonatomic) CGFloat elasticity; @property (readwrite, nonatomic) CGFloat friction; @property (readwrite, nonatomic) CGFloat density;
  • 193. 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;
  • 194. 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;
  • 195. 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;
  • 196. 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;
  • 197. 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;
  • 198. 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
  • 199. 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
  • 200. 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
  • 201. Long Story Short • Identify the type of dynamic items you want to animate
  • 202. Long Story Short • Identify the type of dynamic items you want to animate • Define container or reference view
  • 203. Long Story Short • Identify the type of dynamic items you want to animate • Define container or reference view • Create the behaviours
  • 204. 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
  • 205. 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
  • 207. Custom Behavior • Can subclass UIDynamicBehavior
  • 208. Custom Behavior • Can subclass UIDynamicBehavior • add child behavior - (void)addChildBehavior:(UIDynamicBehavior *)behavior; - (void)removeChildBehavior:(UIDynamicBehavior *)behavior; @property (nonatomic, readonly, copy) NSArray* childBehaviors;
  • 209. 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
  • 210. Example: gravity & collision
  • 211. 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
  • 212. 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
  • 213. 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
  • 214. 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
  • 215. 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
  • 216. 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
  • 217. 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
  • 218. 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
  • 219. 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
  • 220. 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
  • 221. 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
  • 222. 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
  • 223. 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
  • 224. 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
  • 225. 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
  • 226. 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
  • 227. Action Block • Can define per-step actions
  • 228. Action Block • Can define per-step actions @property (nonatomic, copy) void (^action)(void);
  • 229. Action Block • Can define per-step actions @property (nonatomic, copy) void (^action)(void); • UIDynamicAnimator invoke this block in each simulation step
  • 230. 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
  • 232. UIDynamicItem Protocol @protocol UIDynamicItem <NSObject> ! @property (nonatomic, readwrite) CGPoint center; @property (nonatomic, readonly) CGRect bounds; @property (nonatomic, readwrite) CGAffineTransform transform; ! @end
  • 233. 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
  • 234. 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
  • 235. 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
  • 236. 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
  • 237. 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)
  • 238. UIDynamicItem Protocol • center, bounds, and transform are read only once by UIKit
  • 239. UIDynamicItem Protocol • center, bounds, and transform are read only once by UIKit • When adding the item to an animator for the first time
  • 240. 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
  • 241. 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
  • 242. 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
  • 243. 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
  • 244. 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
  • 245. 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
  • 246. UIDynamicItem Protocol • All items animated by UIKit Dynamics must implement this protocol
  • 247. UIDynamicItem Protocol • All items animated by UIKit Dynamics must implement this protocol • UIView conforms to protocol @interface UIView : UIResponder < NSCoding, UIAppearance, UIAppearanceContainer, UIDynamicItem > { ... }
  • 248. 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 > { ... }
  • 249. 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 > { ... }
  • 252. 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
  • 253. 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
  • 254. 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
  • 255. 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
  • 256. 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
  • 257. 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
  • 258. 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
  • 259. 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
  • 260. 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
  • 261. 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
  • 262. 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
  • 263. 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
  • 264. Example 1: conform to UIDynamicItem
  • 265. 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]
  • 266. 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]
  • 267. UIDynamicItem Use Case • Can use a single dynamic item to animate different views
  • 268. UIDynamicItem Use Case • Can use a single dynamic item to animate different views • Can map center or transform to something else
  • 269. 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
  • 270. 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
  • 271. Example 2: remap center property
  • 272. 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
  • 273. 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
  • 274. 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
  • 275. 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
  • 276. 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
  • 277. 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
  • 278. 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
  • 279. 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
  • 280. 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
  • 281. 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
  • 282. 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
  • 283. 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
  • 284. 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
  • 285. 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
  • 286. 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
  • 287. 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
  • 288. Example 2: remap center property
  • 289. 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]
  • 290. 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]
  • 291. 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]
  • 292. 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]
  • 293. 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]
  • 294. 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]
  • 296. Dynamics & UICollectionViews • UICollectionViewLayoutAttributes conform to UIDynamicItem
  • 297. Dynamics & UICollectionViews • UICollectionViewLayoutAttributes conform to UIDynamicItem • Can use UIKit Dynamics with collection view
  • 298. Dynamics & UICollectionViews • UICollectionViewLayoutAttributes conform to UIDynamicItem • Can use UIKit Dynamics with collection view • How
  • 299. Dynamics & UICollectionViews • UICollectionViewLayoutAttributes conform to UIDynamicItem • Can use UIKit Dynamics with collection view • How • Use UIKit Dynamics for very specific animations
  • 300. 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
  • 301. 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
  • 302. 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
  • 303. 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
  • 304. Basic steps • Create the the UICollectionViewLayout instance
  • 305. Basic steps • Create the the UICollectionViewLayout instance • Create the UIDynamicAnimator with layout instance UICollectionViewLayout *layout = ...; animator = [[UIDynamicAnimator alloc] initWithCollectionViewLayout :layout];
  • 306. Basic steps • Create the the UICollectionViewLayout instance • Create the UIDynamicAnimator with layout instance UICollectionViewLayout *layout = ...; animator = [[UIDynamicAnimator alloc] initWithCollectionViewLayout :layout];
  • 307. Basic steps • Create the the UICollectionViewLayout instance • Create the UIDynamicAnimator with layout instance UICollectionViewLayout *layout = ...; animator = [[UIDynamicAnimator alloc] initWithCollectionViewLayout :layout];
  • 308. Basic steps • Create the the UICollectionViewLayout instance • Create the UIDynamicAnimator with layout instance UICollectionViewLayout *layout = ...; animator = [[UIDynamicAnimator alloc] initWithCollectionViewLayout :layout];
  • 309. 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
  • 310. 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]; ...
  • 311. 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]; ...
  • 312. 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]; ...
  • 313. UIKit Dynamics Support for UICollectionViews
  • 314. UIKit Dynamics Support for UICollectionViews Dynamics has convenience support for UICollectionView
  • 315. UIKit Dynamics Support for UICollectionViews Dynamics has convenience support for UICollectionView • Dynamics automatically invalidate layout as needed
  • 316. 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
  • 317. 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
  • 318. 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;
  • 319. 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;
  • 320. 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;
  • 322. Collection View Layout Updates Use usual UICollectionViewLayout methods for layout update: 
  • 323. Collection View Layout Updates Use usual UICollectionViewLayout methods for layout update:  • prepareLayout
  • 324. Collection View Layout Updates Use usual UICollectionViewLayout methods for layout update:  • prepareLayout •used when instantiate an animator or create initial state 
  • 325. Collection View Layout Updates Use usual UICollectionViewLayout methods for layout update:  • prepareLayout •used when instantiate an animator or create initial state  •prepareForCollectionViewUpdates
  • 326. 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
  • 327. 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
  • 328. 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
  • 330. 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
  • 331. 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
  • 332. 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
  • 333. 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
  • 334. 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
  • 335. 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
  • 336. 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
  • 337. 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
  • 338. 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
  • 339. 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
  • 340. 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
  • 341. 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
  • 342. 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
  • 343. 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
  • 344. 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
  • 345. 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
  • 346. 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
  • 347. 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
  • 348. 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
  • 349. 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
  • 350. 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
  • 351. 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
  • 352. 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 ! !
  • 353. 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 ! !
  • 354. 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 ! !
  • 355. 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
  • 356. 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
  • 357. 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
  • 358. 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
  • 359. 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
  • 360. 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
  • 363. Tips • Build iteratively • Check for setup which don’t have solutions
  • 364. Tips • Build iteratively • Check for setup which don’t have solutions
  • 365. Tips • Build iteratively • Check for setup which don’t have solutions
  • 366. Tips • Build iteratively • Check for setup which don’t have solutions • Collision only for rectangle objects
  • 367. Tips • Build iteratively • Check for setup which don’t have solutions • Collision only for rectangle objects
  • 368. Tips • Build iteratively • Check for setup which don’t have solutions • Collision only for rectangle objects • Not an physics-accurate simulation tool
  • 369. 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
  • 370. 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
  • 371. 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
  • 372. Animations and Interactions • Can combine all previous techniques
  • 373. Animations and Interactions • Can combine all previous techniques • Core Animation
  • 374. 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;
  • 375. 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
  • 376. 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
  • 377. Endings "With great power comes great responsibility." Francois-Marie Arouet a.k.a. Voltaire
  • 378. 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
  • 379. 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)
  • 380. Q&A
  • 382. … and one more thing
  • 384. THANKS