Wednesday, March 5, 2014

Punch up your iOS 7 app's wow factor by using UIKit Dynamics

Your can improve the user experience of your iOS 7 apps by incorporating UIKit Dynamics features into your development work. Marcio Valenzuela warns: just don't overdo it

UIKit Dynamics adds a new level of features to the overall user experience (UX) of iOS 7 apps. The API is, however, something to be used sparingly and only when needed; otherwise, you might get user complaints about the bounciness of a table view or the Lock Screen camera button, for example.
It's simple to incorporate UIKit Dynamics into your iOS 7 app. Plus, the end result has a really big wow factor that is certain to impress your users. Let's take a quick conceptual drive around UIKit Dynamics.
First, we adopt the protocol into the ViewController, which will implement UIKit Dynamics. Why? Because the objects that will be animated in the end will have to send back a lot of signals like "Hey, I collided with a boundary" or "Hey, I just hit somebody else and I was going this fast, in this direction." In order to receive these messages, we use a delegate and its callbacks.

@interface … <UICollisionBehaviorDelegate>
We need to create the view to animate and the property to reference a UIDynamicAnimator, which is the object in charge of handling animations in UIKit Dynamics.

@property (nonatomic, weak) IBOutlet UIView *square1;
@property (nonatomic) UIDynamicAnimator* animator;
Basically, we would prep all we need in viewDidLoad, such as instantiating an animator to call the shots inside a particular reference view. Then, we create a behavior or set of behaviors we wish to assign to our animatable view. We define boundaries so we can keep our objects inside a view. Finally, we add the behaviors to the animator and set the viewcontroller as the delegate as well as set that animator object to our property in order to hold a reference to it.
Now we sit back and get messages from the animator and the animated view via the callbacks.

- (void)viewDidLoad
[super viewDidLoad];
IDynamicAnimator* animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
UIGravityBehavior* gravityBeahvior = [[UIGravityBehavior alloc] initWithItems:@[self.square1]];
UICollisionBehavior* collisionBehavior = [[UICollisionBehavior alloc] initWithItems:@[self.square1]];
collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;
or:collisionBehavior]; collisionBehavio
[animator addBehavior:gravityBeahvior]; [animator addBehav ir.collisionDelegate = self; self.animator = animator; }
tForItem:(id<UIDynamicItem>)item withBoundaryIdentifier:(id<NSCopying>)identifier atPoint:(CGPoint)p { // Lighten the background color when the view is in contact w
-(void)collisionBehavior:(UICollisionBehavior *)behavior beganConta cith a boundary. [(UIView*)item setBackgroundColor:[UIColor lightGrayColor]]; } -(void)collisionBehavior:(UICollisionBehavior *)behavior endedContactForItem:(id<UIDynamicItem>)item withBoundaryIdentifier:(id<NSCopying>)identifier
{ // Restore the default color when ending a contcact. [(UIView*)item setBackgroundColor:[UIColor grayColor]];

A simple example

Let's say we are building a restaurant rating app. It's a single view app with a plain vanilla UIViewController that has these properties connected to those outlets:

@property (nonatomic, strong) IBOutlet UILabel *restaurantName;
@property (nonatomic, strong) IBOutlet UILabel *restaurantAddress;
tomic, strong) IBOutlet UIImageView *stars1; @property (non
@property (non aatomic, strong) IBOutlet UIImageView *stars2;
iew *stars3; @property (nonatomic, strong) IBOutlet UIImage
@property (nonatomic, strong) IBOutlet UIImage VView *stars4;
tomic, strong) IBOutlet UIImageView *stars5;
@property (non a
Create the animator that will handle the animation inside our viewDidLoad:

// Create animator
UIDynamicAnimator* animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
Add the views we want to animate to the behaviors we want to implement:

//Create behaviors
UIGravityBehavior* gravityBeahvior = [[UIGravityBehavior alloc] initWithItems:@[self.stars1,self.stars2, self.stars3, self.stars4,self.stars5]];
UICollisionBehavior* collisionBehavior = [[UICollisionBehavior alloc] initWithItems:@[self.stars1,self.stars2, self.stars3, self.stars4,self.stars5]];
IDynamicItemBehavior* propertiesBehavior = [[UIDynamicItemBehavior alloc] initWithItems:@[self.stars1,self.stars2, self.stars3, self.stars4,self.stars5]]; prop
UertiesBehavior.elasticity = 5;
The last behavior is actually created to modify certain physical properties of an object, in this case elasticity. There are other properties we can modify in this manner.
We can also add specific boundaries, but in many cases we will want to simply use the view's edges as the natural boundaries, so we use this line:

collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;
Add the behaviors to the animator, set the delegate to self, and reference our animator through its property:

[animator addBehavior:gravityBeahvior];
[animator addBehavior:collisionBehavior];
ollisionBehavior.collisionDelegate = self;
self.animator = animator;
Finally, add the following delegate callbacks to decide what gets done when a collision occurs:

-(void)collisionBehavior:(UICollisionBehavior *)behavior beganContactForItem:(id<UIDynamicItem>)item withBoundaryIdentifier:(id<NSCopying>)identifier atPoint:(CGPoint)p
{ // Lighten the background color when the view is in contact with a boundary. [(UIView*)item setBackgroundColor:[UIColor lightGrayColor]]; }
// Restore the default color when ending a contcact. [(UIView*)item setBackgroundColor:[UIColor grayColor]]; }
-(void)collisionBehavior:(UICollisionBehavior *)behavior endedContactForItem:(id<UIDynamicItem>)item withBoundaryIdentifier:(id<NSCopying>)identifier
That's it! There are lots of neat effects you can use, but don't overdo it, or your users might complain that you gave them vertigo.