Categories
iOS & ObjectiveC Iphone Developer Technological

iOS7 – UIKit Dynamics

iOS7 Series – UIKit Dynamics

 

Incorporating UIKitDynamics into your app is pretty simple!  The great thing about it is that you really get the most bang for your buck because the end result has a really big WOW Factor which is certain to impress your users.  Let’s take a quick conceptual drive around UIKitDynamics.

First we adopt the protocol into the ViewController which will implement UIKitDynamics, why?  Well because the objects which 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 would need to create the view to animate and the property to reference a UIDynamicAnimator, which is the object in charge of handling animations in UIKitDynamics.

@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.

That’s it!  Now we just sit back and get messages from the animator and the animated view via the callbacks.

– (void)viewDidLoad{

[super viewDidLoad];

UIDynamicAnimator* animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];

UIGravityBehavior* gravityBeahvior = [[UIGravityBehavior alloc] initWithItems:@[self.square1]];

UICollisionBehavior* collisionBehavior = [[UICollisionBehavior alloc] initWithItems:@[self.square1]];

collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;

[animator addBehavior:gravityBeahvior];

[animator addBehavior:collisionBehavior];

collisionBehavior.collisionDelegate = self;

self.animator = animator;

}

-(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]];

}

-(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]];

}

Ok so let’s use it in a simple example.  Let’s say we are building a Restaurant rating app.  It’s a single view app with a plain vanilla UIViewController which has these properties connected to those outlets:

@property (nonatomic, strong) IBOutlet UILabel *restaurantName;

@property (nonatomic, strong) IBOutlet UILabel *restaurantAddress;

//STAR RATING

@property (nonatomic, strong) IBOutlet UIImageView *stars1;

@property (nonatomic, strong) IBOutlet UIImageView *stars2;

@property (nonatomic, strong) IBOutlet UIImageView *stars3;

@property (nonatomic, strong) IBOutlet UIImageView *stars4;

@property (nonatomic, strong) IBOutlet UIImageView *stars5;

 

First let’s create the animator that will handle the animation inside our viewDidLoad:

// Create animator

UIDynamicAnimator* animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];

Now we 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]];

UIDynamicItemBehavior* propertiesBehavior = [[UIDynamicItemBehavior alloc] initWithItems:@[self.stars1,self.stars2, self.stars3, self.stars4,self.stars5]];

propertiesBehavior.elasticity = 5;

Notice that 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;

Finally we add the behaviors to the animator, set the delegate to self and reference our animator through its property:

[animator addBehavior:gravityBeahvior];

[animator addBehavior:collisionBehavior];

collisionBehavior.collisionDelegate = self;

self.animator = animator;

Finally just 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]];

}

-(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]];

}

That’s it!  There are lots of neat effects you can use but don’t overdo it or your users will sue you for giving them vertigo! J

Categories
Iphone Developer Technological

GrandCentralDispatch & Blocks

Grand Central Dispatch iOS
Grand Central Dispatch iOS Santiapps.com by Marcio Valenzuela

GCD helps improve your apps performance and responsiveness by outsourcing processes that require a lot or computing power to the background while keeping your UI responsive.  Normally you might want to do some heavy lifting.

Let’s create an Empty Application.  You need to declare a IBOutlet UIImageView *imageView ivar in your appDelegate, make it a property and synthesize it in .m and make the connection in Interface Builder, IB.  In it’s viewDidLoad method put the following code:

// Download the image
NSURL *url = [NSURL URLWithString:@”http://www.santiapps.com/assets/bbkoko.jpg”];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
NSURLResponse *res = [[NSURLResponse alloc] init];
NSError *err = nil;
NSData *data = nil;
data = [NSURLConnection sendSynchronousRequest:req
returningResponse:&res
error:&err];
// Convert the data to a UIImage
UIImage *image = [UIImage imageWithData:data];

// Scale the image
UIImage *thumbImage = nil;
CGSize newSize = CGSizeMake(90, (90 / image.size.width) * image.size.height);
UIGraphicsBeginImageContext(newSize);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
thumbImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

// Add this to a UIImageView
self.imageView.image = thumbImage;

If you load this up, you’ll notice it’ll take quite some time to load.  Analyzing this code you notice that the heaviest workload is the NSURL request. Ideally we would like to dispatch this to a separate queue so that the app doesn’t stall while this is happening. BTW, the best way to see how a task like this stalls your app’s launch is to place the code right into your applicationDidFinishLaunching, which will stall the display of the MainWindow.xib.

Run the code as is and you’ll notice how the app hangs on the black screen before displaying the default white colored MainWindow.xib background.

So what we want to do is throw this out into a side queue so as to not hold up the presenting of the UI of the app. Grand Central Dispatch, or GCD for short, is ideal for this. First add this line to your AppDelegate, or whatever the class you are using it in:

#import <dispatch/dispatch.h>

Then fix your code to implement GCD:

dispatch_queue_t downloadQueue = dispatch_queue_create(“imageDL”, NULL);
dispatch_async(downloadQueue, ^{

NSURL *url = [NSURL URLWithString:@”http://www.santiapps.com/assets/bbkoko.jpg”];
NSURLRequest *req = [NSURLRequest requestWithURL:url];
NSURLResponse *res = [[NSURLResponse alloc] init];
NSError *err = nil;
NSData *data = nil;
data = [NSURLConnection sendSynchronousRequest:req
returningResponse:&res
error:&err];
     dispatch_async(dispatch_get_main_queue(), ^{

// Convert the data to a UIImage
UIImage *image = [UIImage imageWithData:data];

// Scale the image
UIImage *thumbImage = nil;
CGSize newSize = CGSizeMake(90, (90 / image.size.width) * image.size.height);
UIGraphicsBeginImageContext(newSize);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
thumbImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

// Add this to a UIImageView
self.imageView.image = thumbImage;

});

});

dispatch_release(downloadQueue);

Run it now and notice how fast the MainWindow.xib pops up on the screen and later displays the image once it has downloaded.

If you want to get a more live view of how GCD works, try this code out in an app:

Simple Block Time Example
           

             NSDate *date = [NSDate date];

void (^now)(void) = ^ {

NSLog(@”The date and time is %@”, date);
};

now();
date = [NSDate date];
sleep(5);

now();

You should see in your console the time logging every 5 seconds.

GCD is very helpful for sending off queues that take a long time (like web fetches – images or db queries – image processing etc).  Your app is still usable while the heavy work is done on another thread that doesn’t obstruct your main thread which is where UIKit stuff used by the user, is handled.

Categories
Technological

iOS UI Refresh

iOS is undoubtedly a great touch UI. However, it needs a refresh, it’s long overdue for an overhaul.  Not just a “new widget” type refresh but a real overhaul.  If we can make a robot that flies millions of miles to explore a hostile planet…

SEARCHING FOR APPS

The whole repetitive process of searching for apps in the AppStore, installing them, updating them everyday and switching between them is getting so old, so 2012!

We’re are in the era of Robots that travel millions of space miles to do their thing. Robots that park cars, help the elderly etc. Our robots are getting smarter by the day. We need our smartphone to get smarter too.

Finding apps is a real pain. Not only is the AppStore not very good at finding apps for you, but the whole idea of searching for an app is tedious. A smartphone should really recommend apps based on our preferences. More importantly it should gives us a dashboard of the apps we haven’t used lately, suggest similar apps to those so we may decide to replace them and preset us with new apps altogether. New featured apps should be based on our preferences, not user ratings. What do I care if 500 million kids really love games and have access to their mom and pop’s credit card!? My featured apps need to be customized to my lifestyle, not a voting system.

The dashboard should be smart enough to look at what apps I have, types of documents I store on iCloud or Dropbox, most visited locations etc and come up with app suggestions that are really productive.

INSTALLING APPS

Installing apps is also rather tedious.  Once you find the app you still have to touch install and enter your password.  iOS screens should be sensitive enough to detect fingerprint patterns or have voice control for entering passwords orally.  This “popping the keyboard to type in passwords that get more complex every day due to hackers” thing is a bit annoying.  I completely agree with the need for security not only from strangers who might have gotten ahold of your phone but also little kids who might buy a slew of games on your device while you are not paying attention.  But adding a bunch of obstacles makes it a pain for those 5 to 10 minutes you do manage to pry the device from your kids’ hands and you want to actually buy an app.

UPDATING APPS

Updating is just as bad as installing.  No wait…its worse!  You only install once.  You update every time the developer comes up with a new update, which can be quite often.  Its annoying to see those red badges in the AppStore app reminding you of a pending update.  As if that wasn’t enough, you have to re-enter your password if you wish to update an app you already downloaded.  If the app cost anything, you don’t have to pay to upgrade it, so why ask for the password?  It won’t cost the user more money to upgrade it.  If you already downloaded it in the first place, why would you not want to have it upgraded?  Who wants to pay for an app but doesn’t want the new and improved features of it?  If you are going to ask the user, “the app you have has new improvements ready to be downloaded for free, do you wish to download the new version that won’t cost you a penny?”, then at least ask “Or would you like to see these other apps that have similar functionality?”.  At least you will have made it worthwhile to make the user re-enter the long convoluted password in the tiny keyboard :).

SWITCHING APPS

This is perhaps the toughest feature to address.  iPad has done wonders with its sideways swipe to switch between apps or its upwards swipe to view open apps.  iPhone needs to at least get up to speed somehow.  I constantly find myself switching from twitter to facebook to email to browser.  Wouldn’t it be nice if the smartphone was actually smart enough to know what to do next?  For example, I have a usage pattern; when I wake up, I check facebook and then twitter, or vv.  It would be nice to click on the home button or voice control over to an action sheet with app launching options.  When leaving the facebook app, the user should be presented with options based on what he regularly does after facebook, or based on what would be a logical step after facebook.

The whole square icons on a grid app model needs to be revised.  Ill be honest, I don’t have a Windows phone, but I have heard it is one of the most touted advantages of the OS.  I have never used it so I don’t know if it’s really true or not but it is definitely something worth looking into because this whole switching between apps is really getting old.

Here is to hoping that iOS7 will bring something new.  Here is to hoping iOS7 won’t be another WindowsMe.