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 !

Thursday 8 May 2014

Create custom code snippet in Xcode

Concern:

Xcode comes with inbuilt code snippet library to provide code skeleton to implement repeatedly used code quickly.

Fortunately we can update this list of snippets in library and add our own custom snippet which we need most of the time in our life!

 

Outcome: 

Our own custom snippet to save implementation time.
 

Description: 

we have been using many of the snippet in Xcode which makes it easier to implement code like for, while, switch and most used init code snippet.
 

Let's add our own custom code snippet, by taking example NSString method -  
+ (instancetype)stringWithFormat:(NSString *)format;

for example, with out code snippet we have to type all the syntax every time we want to implement this method, [NSString stringWithFormat:@"%@",];

Now lets add snippet for this,
  • Type statement which you want to come up automatically on calling snippet.
         [NSString stringWithFormat:@"", ];
  • Select and Add this code to snippet library.
Select code and drag it to snippet library, which can be activated by  View > Utilizes > Show Code Snippet Library or press control + option + cmd + 2 in Xcode.
On success, we will find New snippet added in library named "My Code Snippet".
  • Edit snippet
Click newly added snippet to activate snippet summery pop up.
Click on edit, which will allow to modify snippet more specifically.
  1. Title, is a snippet name by which that snippet will be called
  2. Summery, which shows brief function of snippet
  3. Platform, allows to select platform OS X or iOS or Both
  4. Language, allows to specify language snippet belongs to
  5. Completion Shortcut, allows to set shortcut for snippet
  6. Completion Scope, allows to set scope, where snippet will be available
  • For our example,


Title : strWithFormate

Summary : snippet for stringWithFormat
Platform : All
Language : Objective C

Completion Shortcut : strWithFormate
Completion Scope : All
  • Add bubble to accept values
edit snippet code by,
[NSString stringWithFormat:@"<#type#>", <#expression#>];
which adds bubble to accept values for data type and expression we are going to log.
  • Done!
    Now if we type strWithFormate and hit enter, we will get
     [NSString stringWithFormat:@"<#type#>", <#expression#>];
    and by pressing TAB, we will able to assign values to pre populated bubbles.


Conclusion:

Before: 
 



After:


 

Comments / Suggestions are welcomed!