Thursday 22 May 2014

Introducing UIKit Dynamics

Concern : As animation is so important and allows to represent things in more realistic manner, iOS 7 came with new catalog UIKit Dynamics. lets adopt it!

Outcome : Idea & understanding of UIKit Dynamics and concern things.

Description :

  • UIKit Dynamics which has been introduced from iOS 7, facilitate typical UIViews which conforms to   UIDynamicItem  protocol to behave more lively.
  • New framework allow us to relate our UIKit views with real life factors like gravity, resistance, friction, collision and so on.
  • Dynamics on views can be achieved by directly adding primitive behaviour and also by adding custom behaviour which may be combination of primitive behaviours.

Main Roles:     

  • Two components playing main or say major roles to dynamics let happen, which are :
  1. UIDynamicAnimator  :
    - Acts as UIKit physics engine.
    - Takes reference of  UIView which aspire to adopt dynamics.
    - Accepts various UIDynamicBehaviours and make referenced view to act accordingly.
  2. UIDynamicBehaviour :
- Allows to configure view behaviour in physics (real) world.
- Inherited by primitive dynamic behaviours which are,

UIGravityBehavior,
To make our dynamic view real and alive, we can apply gravity on it by this behaviour which makes view to fall within referenced view as if it is in real world.

     
UIAttachmentBehavior,
As name suggest, this behaviour allows view to act as if it attached to some point in referenced view and also with other dynamic item.

UICollisionBehavior,
When our views move there is a chance of collision between them or with the boundaries of the referenced view.

By using this behaviour this kind of collision can be handled in more subtle way. Boundaries for the collision can be defined as bound of referenced view or any other boundary defined by lines or Bezier path. 

      
UIPushBehavior
,
Simulates effect of pushing dynamic items in specific direction with defined force.

Two kind of forces : 

Instantaneous:
 acts as sudden strong push at once, which will result in quick velocity gain at start, which gradually lose momentum and eventually stops.

Continuous:  is applied continuously on dynamic item causing gradual acceleration. 


UISnapBehavior,

Allows to add snap behaviour on view, by which view behaves as if it is pulled suddenly and will stop at given point by completing oscillation specified in form damping.


UIDynamicItemBehavior,
Allows to add additional properties like density, friction, rotation etc to dynamic items which will affect primitive behaviours and hence dynamic item behaviour.

     - can be inherited by custom class to achieve more custom behaviour.

Lets see how to achieve this by code,
    Configure UIDynamicBehaviours
  • // get UIGravityBehavior instance
    UIGravityBehavior *gravityBehavior =
    [[UIGravityBehavior alloc]initWithItems:@[view1, view2, ...]];
    
    // set gravity direction
    CGVector vector = CGVectorMake(0.5, 0.5);
    [gravityBehavior setGravityDirection:vector];
    
    // For customised gravity behaviour set Angle,magnitude
    gravityBehavior.angle = DEGREES_TO_RADIANS(45);
    gravityBehavior.magnitude = 2.0f;
    
    

  • BreakPoint :
    • The default value for the gravity vector is (0.0, 1.0)
    • The acceleration for a dynamic item subject to a (0.0, 1.0) gravity vector is downwards at 1000 points per second²
    • magnitude of 2.0 represents an acceleration of 2000 points / second²

    - UICollisionBehavior
  • //collision behaviour between view1 and view2, which results in real time collision between these views and based on their characteristics like angle,magnitude etc. physics engine will apply effect on views as per physics law.
    
    UICollisionBehavior *collisionBehaviour =
    [[UICollisionBehavior alloc] initWithItems:@[view1, view2]];
    
    
    //convert referenced view bound as collision boundary, which will stop views to go out of the screen bound.
    collisionBehaviour.translatesReferenceBoundsIntoBoundary = YES;
    
    //set boundary other than referenced view bounds, by setting insets
    collisionBehaviour.setTranslatesReferenceBoundsIntoBoundaryWithInsets:UIEdgeInsetsMake(20.0f, 20.0f, 20.0f, 20.0f);
    
    

  • Some variant of collision modes,  
  • collisionBehaviour.collisionMode = UICollisionBehaviorModeItems;
    
  • (saying that collision will occur only with views involved in collision behaviour, no collision with boundary)

  • collisionBehaviour.collisionMode = UICollisionBehaviorModeBoundaries;
    
    
  • (saying that views will not collide internally, only collision with boundary)

  • collisionBehaviour.collisionMode = UICollisionBehaviorModeEverything;
    
  • (saying that collision will occur with views internally as well as with boundary, this is DEFAULT mode if we do not specify externally)

    - Fortunately UICollisionBehavior comes with UICollisionBehaviorDelegate, which allows to get notifications on each collision to perform customised actions on views.

  • // implement delegate 
    @interface ViewController () <UICollisionBehaviorDelegate>
     
    @end
    
    
    //set delegate collisionBehaviour collisionBehaviour.collisionDelegate = self;
    // implement following methods depending on case - (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; // The identifier of a boundary created with translatesReferenceBoundsIntoBoundary or setTranslatesReferenceBoundsIntoBoundaryWithInsets is nil - (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;
    // Ex. removing items on collision - (void)collisionBehavior:(UICollisionBehavior *)behavior beganContactForItem:(id <UIDynamicItem>)item1 withItem:(id <UIDynamicItem>)item2 atPoint:(CGPoint)p{ [(UIView *)item1 removeFromSuperview]; [(UIView *)item2 removeFromSuperview]; }

  • - UIAttachmentBehavior
  • UIAttachmentBehavior *attachmentBehaviour = [[UIAttachmentBehavior alloc] initWithItem:view1 attachedToItem:view2];
    
  • (Saying that view1 is attached to view2, considering no offset from center of views i.e centre point of views are taken as base)

  • CGPoint anchorpoint = CGPointMake(500, 500);
    UIAttachmentBehavior  *attachmentBehaviour = [[UIAttachmentBehavior alloc] initWithItem:view1
    attachedToAnchor:anchorpoint];
    [attachmentBehaviour setFrequency:5.0];
    [attachmentBehaviour setDamping:0.5];
    
  • (Saying that view1 is attached to point (500, 500) of referenced view, with considering centre of view1 as base)

    BreakPoint :


  • CGPoint anchorpoint = CGPointMake(500, 500);
    UIOffset offset = UIOffsetMake(40, 40);
    UIAttachmentBehavior *attachmentBehaviour = [[UIAttachmentBehavior alloc] initWithItem:view1
    offsetFromCenter:offset attachedToAnchor:anchorpoint];
    
  • (Saying that view1 is attached to point (500,500) of referenced view with considering point calculated by offset for centre point)

    - UISnapBehavior

  • CGPoint point = CGPointMake(100, 100);
    
    UISnapBehavior *snapBehaviour =
    [[UISnapBehavior alloc]initWithItem:view1 snapToPoint:point];
    
    snapBehaviour.damping = 1.0;
    
    
  • (Saying that view1 is to be snapped to point (100,100) )

    BreakPoint :
    • value of damping ranges between 0.0 to 1.0, 1.0 results in maximum oscillation

    - UIPushBehavior


  • UIPushBehavior *pushBehavior = [[UIPushBehavior alloc] initWithItems:@[view1] mode:UIPushBehaviorModeInstantaneous];
    
    or
    
    UIPushBehavior *pushBehavior = [[UIPushBehavior alloc] initWithItems:@[view1] mode:UIPushBehaviorModeContinuous];
    
    pushBehavior.magnitude = 5.0f;
    
    CGVector vector = CGVectorMake(0.2, 0.2);
    
    pushBehavior.pushDirection = vector;
    
    
  • (Saying that view1 is liable for instantaneous or continuous force at specified vector & magnitude applied)

    BreakPoint :
    • By default push is applied to centre of dynamic item unless offset of attachment is set.
    • default magnitude is nil equivalent to no force.
    • A continuous force vector with a magnitude of 1.0, applied to a 100 point x 100 point view whose density value is 1.0, results in view acceleration of 100 points / second² in the direction indicated by the angle or pushDirection property.
    • The default x and y values of the push direction vector are each 0.0. A value for either component of 1.0, applied to a 100 point x 100 point view, whose density value is 1.0,results in view acceleration of 100 points / second² in the positive direction for the component.

    - UIDynamicItemBehavior


  • //intiate instance with referenced view
    UIDynamicItemBehavior *dynamicBehavior = [[UIDynamicItemBehavior alloc]
    initWithItems:@[view1, view2, ...]];
    
    //set elasticity, higher elasticity makes item more bouncy
    dynamicBehavior.elasticity = 0.2;
    
    //set overall resistance, greater resistance yields sooner animation / effect stop
    dynamicBehavior.resistance = 0.5;
    
    //set friction, resistance when item collides with other items
    dynamicBehavior.friction = 0.5;
    
    //set density, mass of item - higher mass makes hard to accelerate and decelerate item
    dynamicBehavior.density = 1.0;
    
    // allow rotation, flag to enable/disable rotation
    dynamicBehavior.allowsRotation = TRUE;
    
    //set angularResistence,resistance for rotation - higher value makes rotation to stop sooner
    dynamicBehavior.angularResistance = 0.5;
    
    //add angular velocity, increase or decrease angular velocity of view by positive or negative value respectively measured in radian per second
    [dynamicBehavior addAngularVelocity:10.0 forItem:view1];
    
    //add linear velocity, increase or decrease angular velocity of view by positive or negative value respectively measured in points per second
    [dynamicBehavior addLinearVelocity:CGPointMake(150, 150) forItem:view1];
    
    

  • - Combination of behaviours
  • // Create multiple behavior objects here
    
    UIDynamicBehavior *combinedBehavior = [[UIDynamicBehavior alloc]init];
    
    [combinedBehavior addChildBehavior:gravityBehavior];
    [combinedBehavior addChildBehavior:collisionBehaviour];
    [combinedBehavior addChildBehavior:attachmentBehaviour];
    [combinedBehavior addChildBehavior:snapBehaviour];
    
    
    //add / remove item from behaviour
    [gravityBehavior addItem:view3];
    [attachmentBehaviour removeItem:view1];
    
    

  • Configure UIDynamicAnimator
  • @property (strong, nonatomic) UIDynamicAnimator *animator;
    
    _animator = [[UIDynamicAnimator alloc] 
    initWithReferenceView:self.view];
    
    // add behaviours to animator to make it live
    [_animator addBehavior: gravityBehavior];
    [_animator addBehavior: collisionBehaviour];
    [_animator addBehavior: attachmentBehaviour];
    [_animator addBehavior: snapBehaviour];
    [_animator addBehavior: combinedBehavior];
    

Conclusion : UIKit Dynamics is amazing new feature which can add life to application, by adding real world like effects and animations.

Taking imagination to next level !

No comments :

Post a Comment