<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:series="http://unfoldingneurons.com/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"> <channel><title>Mobiletuts+</title> <link>http://mobile.tutsplus.com</link> <description>iPhone, Android, Windows and BlackBerry mobile development tutorials.</description> <lastBuildDate>Tue, 18 Jun 2013 16:03:32 +0000</lastBuildDate> <language /> <sy:updatePeriod>hourly</sy:updatePeriod> <sy:updateFrequency>1</sy:updateFrequency> <generator>http://wordpress.org/?v=3.5</generator> <atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/MobileTuts" /><feedburner:info uri="mobiletuts" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>MobileTuts</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item><title>Build a Monster Smashing Game with Cocos2D: Sound &amp; Game Mechanics</title><link>http://feedproxy.google.com/~r/MobileTuts/~3/OFzjhPbQzAE/</link> <comments>http://mobile.tutsplus.com/tutorials/iphone/build-a-monster-smashing-game-with-cocos2d-sound-game-mechanics/#comments</comments> <pubDate>Tue, 18 Jun 2013 16:02:07 +0000</pubDate> <dc:creator>Jorge Costa and Orlando Pereira</dc:creator> <category><![CDATA[Game Engines]]></category> <category><![CDATA[iOS SDK]]></category> <guid isPermaLink="false">http://mobile.tutsplus.com/?p=17408</guid> <description>&lt;p&gt;This tutorial will teach you how to use the Cocos2D iOS framework in order to create simple yet advanced 2D games aimed at all iOS devices. It&amp;#8217;s designed for both novice and advanced users. Along the way, you&amp;#8217;ll learn about the Cocos2D core concepts, touch interaction, menus and transitions, actions, particles, and collisions. Read on!&lt;br
/&gt;&lt;/p&gt;&lt;hr
/&gt; Organization of the Series:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a
href="http://mobile.tutsplus.com/?p=17352"&gt;Project Structure &amp;#038; Setup&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a
href="http://mobile.tutsplus.com/?p=17365"&gt;Movement &amp;#038; Animations&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a
href="http://mobile.tutsplus.com/?p=17408"&gt;Sound &amp;#038; Game Mechanics&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;This entry is the third and final tutorial in the series &lt;strong&gt;Monster Smashing&lt;/strong&gt;. Make sure that you&amp;#8217;ve completed the previous tutorial before beginning.&lt;/p&gt;&lt;p&gt;In today&amp;#8217;s tutorial, we&amp;#8217;ll focus on finishing up the game. We&amp;#8217;ll add several properties, including particles, labels, sound, and music. We&amp;#8217;ll use the properties list for monster creation. We&amp;#8217;ll also learn how to correctly pause and resume the Cocos2D data flow process without too much processing power.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;1.&lt;/span&gt; Lives&lt;/h2&gt;&lt;p&gt;The label system in games is normally used for scores, lives, or other related information. In this tutorial we&amp;#8217;ll only use player lives. Each life is represented with a heart on the top left side of screen. The heart image is in the resources.&lt;/p&gt;&lt;p&gt;The user will start the game with three lives. To do this, we initialize the heartArray and use the &lt;code&gt;for&lt;/code&gt; loop to receive the images for each life. We also set the position of the three lives on the top left of the screen.&lt;/p&gt;&lt;p&gt;The first step is to add two new properties, &lt;code&gt;NSMutableArray *hearthArray&lt;/code&gt; and &lt;code&gt;NSInteger lives&lt;/code&gt;, to the &lt;code&gt;MonsterRun.h&lt;/code&gt; class. With that done we can now add the correct implementation, &lt;code&gt;MonstrRun.m&lt;/code&gt;. The following snippet will help us do that.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
    lives = 3;
    hearthArray = [[NSMutableArray alloc] init];
    for(NSInteger i = 0; i lives; i++){
    CCSprite *hearth = [CCSprite spriteWithFile:@&amp;quot;hearth.png&amp;quot;];
    [hearthArray insertObject:hearth atIndex:i];
    hearth.position = ccp( ((i+1)*50), winSize.height - 50);
    [self addChild:hearth];
    }
&lt;/pre&gt;&lt;p&gt;Now if you run the project, you&amp;#8217;ll see the the lives at the top of the screen. However, we can&amp;#8217;t interact with them yet. The next step is to interact with them and make the player lose some lives.&lt;/p&gt;&lt;p&gt;In the method &lt;code&gt;addMonster:(ccTime)dt&lt;/code&gt; in the Block 4 section inside the &lt;code&gt;CCCallBlockN&lt;/code&gt; function, we should add the following snippet.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
    lives--;
    [self removeChild:[hearthArray lastObject] cleanup:YES];
    [hearthArray removeLastObject];
    if(lives == 0)
        [[CCDirector sharedDirector] replaceScene:[HelloWorldLayer scene]];
&lt;/pre&gt;&lt;p&gt;Note that you should add it twice, one for each &lt;code&gt;if&lt;/code&gt; statement.&lt;/p&gt;&lt;p&gt;The code will be called every time a sprite (monster) leaves the screen. If a monster leaves the screen, a life will be lost and at the same time the array of hearts (heartArray) will be changed, and the last position will be removed. The image on screen will also be removed.&lt;/p&gt;&lt;p&gt;If we reach zero lives, the game will stop and we&amp;#8217;re sent back to the initial screen.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;2.&lt;/span&gt; Particles&lt;/h2&gt;&lt;p&gt;Particles are an effect used to achieve, among other things, several effects such as fire, smoke, or waterfalls. In this case, we&amp;#8217;ll use them to explode the red monster. Every time a red monster is touched, we activate the particle.&lt;/p&gt;&lt;p&gt;In part two, we left that section incomplete. Now is the time to finish it.&lt;/p&gt;&lt;p&gt;Add the following property &lt;code&gt;CCParticleExplosion *particleExplosion&lt;/code&gt; to the &lt;code&gt;MonsterRun.h&lt;/code&gt; class. In the &lt;code&gt;-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event&lt;/code&gt; method, where we have the &lt;code&gt;if([m killMethod] == 2)&lt;/code&gt; condition, we&amp;#8217;ll add a new piece of code.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
    CCCallFuncND *emitter = [CCCallFuncND actionWithTarget:self selector:@selector(startExplosion:data:) data:monster];
    CCSequence *sequencia = [CCSequence actions:emitter, nil];
    if([defaults integerForKey:@&amp;quot;sound&amp;quot;]==1)
        [[SimpleAudioEngine sharedEngine] playEffect:@&amp;quot;SplatEffect.caf&amp;quot;];
    [splashPool runAction:sequencia];
[/sourcecode]
This code will provide the necessary requirements for the particle system. First we use the &amp;lt;code&amp;gt;CCCallFuncND&amp;lt;/code&amp;gt; to call a selector &amp;lt;code&amp;gt;startExplosion:data:&amp;lt;/code&amp;gt;. Then we create a particle sequence calling the above-mention &amp;quot;&amp;lt;strong&amp;gt;emitter&amp;lt;/strong&amp;gt;&amp;quot; object.
The next step is to create the &amp;lt;code&amp;gt;CCParticleExplosion *particleExplosion&amp;lt;/code&amp;gt; method. For that you can simply copy and paste the following snippet.
[sourcecode language=&amp;quot;objective c&amp;quot;][/sourcecode]
//Positions the explosion emitter and sets it off
- (void)startExplosion:(id)sender data:(CCSprite*)monster {
    particleExplosion = [[CCParticleExplosion alloc] initWithTotalParticles:809];
    particleExplosion.texture = [[CCTextureCache sharedTextureCache] addImage:@&amp;quot;textureRed.png&amp;quot;];
    particleExplosion.life = 0.0f;
    particleExplosion.lifeVar = 0.708f;
    particleExplosion.startSize = 40;
    particleExplosion.startSizeVar = 38;
    particleExplosion.endSize = 14;
    particleExplosion.endSizeVar = 0;
    particleExplosion.angle = 360;
    particleExplosion.angleVar = 360;
    particleExplosion.speed = 243;
    particleExplosion.speedVar = 1;
    CGPoint g = CGPointMake(1.15, 1.58);
    particleExplosion.gravity = g;
    ccColor4F startC =  {0.89f, 0.56f, 0.36f, 1.0f};
    particleExplosion.startColor = startC;
    ccColor4F endC = {1.0f,0.0f,0.0f,1.0f};
    particleExplosion.endColor = endC;
    [self addChild:particleExplosion];
    particleExplosion.position = [monster position];
    [particleExplosion resetSystem];
}
&lt;/pre&gt;&lt;p&gt;This method will&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Allocate for the &lt;strong&gt;particleExplosion&lt;/strong&gt; property.&lt;/li&gt;&lt;li&gt;Define the total particles count (809).&lt;/li&gt;&lt;li&gt;Define the particle texture (CCTextureCache)&lt;/li&gt;&lt;li&gt;Define several properties, such as start and end size, angle, speed, and color.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;After the particle is configured, we can put it in the center of the monster. The particle explosion will always move when the monster is moving, and it will always be centered.&lt;/p&gt;&lt;p&gt;You can now build and run the project. An example of the particle explosion can be seen in the next image.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Cocos2D-Tutorial_Part-Three_1.png" alt="Figure 1: Particles Example" /&gt;&lt;/p&gt; &lt;figcaption&gt;Illustration of the particle system.&lt;/figcaption&gt; &lt;/figure&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;3.&lt;/span&gt; Sound and Music&lt;/h2&gt;&lt;p&gt;Sound effects and background music are assets to all games. In this section, we&amp;#8217;ll explain how to add them into this game. We&amp;#8217;ll have two types of sounds, a monster click and the background music.&lt;/p&gt;&lt;p&gt;Audio in iOS devices is achieved using the Simple Audio Engine. In order to activate it, import the &lt;code&gt;SimpleAudioEngine.h&lt;/code&gt; at the &lt;code&gt;HelloWorldLayer.m&lt;/code&gt; and &lt;code&gt;MonsterRun.m&lt;/code&gt; classes.&lt;/p&gt;&lt;p&gt;At the &lt;code&gt;HelloWorldLayer.m&lt;/code&gt;, we have several steps to do. The first one is to add the &lt;code&gt;CCMenuItem *_soundOn&lt;/code&gt; property before the &lt;code&gt;@implementation&lt;/code&gt; section.&lt;/p&gt;&lt;p&gt;It should look like this:&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
#import &amp;quot;HelloWorldLayer.h&amp;quot;
#import &amp;quot;AppDelegate.h&amp;quot;
#import &amp;quot;MonsterRun.h&amp;quot;
#import &amp;quot;SimpleAudioEngine.h&amp;quot;
CCMenuItem *_soundOn;
// HelloWorldLayer implementation
@implementation HelloWorldLayer
...
&lt;/pre&gt;&lt;p&gt;Now we can move to the &lt;code&gt;-(id) init&lt;/code&gt; method. We chose to use the &lt;code&gt;NSUserDefaults&lt;/code&gt; class to help us to store the user preferences regarding the sound option. We will first define a number with the &lt;strong&gt;1&lt;/strong&gt; value (with sound) and store it using the &amp;#8220;&lt;strong&gt;sound&lt;/strong&gt;&amp;#8221; key. The next step is to verify the value of the &amp;#8220;&lt;strong&gt;sound&lt;/strong&gt;&amp;#8221; key, and react accordingly to that value. If the value is &lt;strong&gt;1&lt;/strong&gt;, the sound system is initialized. Otherwise, it remains paused.&lt;/p&gt;&lt;p&gt;The following snippet shows this implementation.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
// Check the sound system
    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSObject * object = [defaults objectForKey:@&amp;quot;sound&amp;quot;];
    if(object == nil){
        NSNumber *soundValue = [[NSNumber alloc ] initWithInt:1];
        [defaults setObject:soundValue forKey:@&amp;quot;sound&amp;quot;];
    }
    int soundDefault = [defaults integerForKey:@&amp;quot;sound&amp;quot;];
    if (soundDefault == 1) {
            [[SimpleAudioEngine sharedEngine] playBackgroundMusic:@&amp;quot;backgroundSound.caf&amp;quot;];
            [[SimpleAudioEngine sharedEngine] setEffectsVolume:0.4f];
        }
        else {
            [[SimpleAudioEngine sharedEngine] pauseBackgroundMusic];
        }
&lt;/pre&gt;&lt;p&gt;Now you can modify the &lt;code&gt;CCMenuItemToggle *toggleItem&lt;/code&gt;.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
CCMenuItemToggle *toggleItem;
        if(soundDefault == 1)
            toggleItem = [CCMenuItemToggle itemWithTarget:self selector:@selector(soundButtonTapped:) items:_soundOn, _soundOff, nil];
        else
            toggleItem = [CCMenuItemToggle itemWithTarget:self selector:@selector(soundButtonTapped:) items:_soundOff,_soundOn, nil];
&lt;/pre&gt;&lt;p&gt;With this change, the menu will change according to the user&amp;#8217;s sound preferences. Note that the &lt;code&gt;toggleItem&lt;/code&gt; calls a selector &lt;code&gt;soundButtonTapped:&lt;/code&gt;, so we&amp;#8217;ll need to write that method and create the right logic to verify the toggle button. If the toggle button is selected to &lt;code&gt;_soundOn&lt;/code&gt;, we should start the sound and store &lt;strong&gt;1&lt;/strong&gt; in the &lt;code&gt;NSUserDefaults&lt;/code&gt; preferences. If the toggle button is selected to &lt;code&gt;_soundOff&lt;/code&gt;, we should pause the background music and store &lt;strong&gt;0&lt;/strong&gt; in the &lt;code&gt;NSUserDefaults&lt;/code&gt; preferences.&lt;/p&gt;&lt;p&gt;Use the following snippet to that effect.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
- (void)soundButtonTapped:(id)sender {
    CCMenuItemToggle *toggleItem = (CCMenuItemToggle *)sender;
    if (toggleItem.selectedItem == _soundOn) {
        NSLog(@&amp;quot;Sound Enabled&amp;quot;);
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
        [[SimpleAudioEngine sharedEngine] playBackgroundMusic:@&amp;quot;backgroundSound.caf&amp;quot;];
        [defaults setInteger:1 forKey:@&amp;quot;sound&amp;quot;];
        [defaults synchronize];
    } else {
        NSLog(@&amp;quot;Sound Disabled&amp;quot;);
        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
        [defaults setInteger:0 forKey:@&amp;quot;sound&amp;quot;];
        [[SimpleAudioEngine sharedEngine] pauseBackgroundMusic];
        [defaults synchronize];
    }
}
&lt;/pre&gt;&lt;p&gt;Now we must also change the &lt;code&gt;MonsterRun.m&lt;/code&gt; class. We must add the &lt;code&gt;NSUserDefaults *defaults;&lt;/code&gt; global property. Next, we&amp;#8217;ll initialize it and verify the user&amp;#8217;s sound preferences. The following snippet will help us achieve that.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
- (void)soundButtonTapped:(id)sender {
    defaults = [NSUserDefaults standardUserDefaults];
        int soundDefault = [defaults integerForKey:@&amp;quot;sound&amp;quot;];
        if (soundDefault == 1) {
            [[SimpleAudioEngine sharedEngine] playBackgroundMusic:@&amp;quot;backgroundSound.caf&amp;quot;];
            [[SimpleAudioEngine sharedEngine] setEffectsVolume:0.4f];
        }
&lt;/pre&gt;&lt;p&gt;With this code we can add background sound and a way for the user to control it using the default system preferences. You can now run the project and play with the sound button in order to test the new sound property.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;4.&lt;/span&gt; Properties List&lt;/h2&gt;&lt;p&gt;Property lists (&lt;strong&gt;plist&lt;/strong&gt;) are a useful resource for storing information regarding the game&amp;#8217;s environment and evolution. In our case, we&amp;#8217;ll store information regarding the monsters. The plist created (&lt;strong&gt;Enemy.plist&lt;/strong&gt;) can be seen in the next image.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Cocos2D-Tutorial_Part-Three_2.png" alt="Figure 2: plist illustration" /&gt;&lt;/p&gt; &lt;figcaption&gt;Illustration of the enemy plist.&lt;/figcaption&gt; &lt;/figure&gt;&lt;p&gt;We will not discuss the best way to create or parse the plist. We&amp;#8217;ll focus on this plist and a possible way to parse the data from it.&lt;/p&gt;&lt;p&gt;The first step is to add the plist to the project. Click &lt;strong&gt;File -&gt; New -&gt; File&lt;/strong&gt; and choose from the right side the option resource, and then the property list (on the left). Name it &lt;strong&gt;Enemy.plist&lt;/strong&gt; and add the information from the previous image.&lt;/p&gt;&lt;p&gt;Now we should parse the data and use it to create the monsters with that information. We first create a string with the path to the plist file, and then we create a dictionary that will store the information inside the plist. The final step is to retrieve the monster&amp;#8217;s options. For each monster, we&amp;#8217;ll add those same properties to them.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
    // plist reading
        NSString * plistPath = [[NSBundle mainBundle] pathForResource:@&amp;quot;Enemy&amp;quot; ofType:@&amp;quot;plist&amp;quot;];
        NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:plistPath];
        // load monster information from pList
        if ([dictionary objectForKey:@&amp;quot;Monsters&amp;quot; ] != nil ){
            NSMutableArray *array = [dictionary objectForKey:@&amp;quot;Monsters&amp;quot;];
            for(int i = 0; i &amp;lt; [array count]; i++){
                NSMutableDictionary *m = [array objectAtIndex:i];
                Monster *m1 = [[Monster alloc] init];
                [m1 setTag:(i+1)];
                [m1 setMonsterSprite:[[NSString alloc] initWithString:[m objectForKey:@&amp;quot;monsterSprite&amp;quot;]]];
                [m1 setSplashSprite:[[NSString alloc] initWithString:[m objectForKey:@&amp;quot;splashSprite&amp;quot;]]];
                [m1 setMinVelocity:[[m objectForKey:@&amp;quot;minVelocity&amp;quot;] floatValue]];
                [m1 setMaxVelocity:[[m objectForKey:@&amp;quot;maxVelocity&amp;quot;] floatValue]];
                [m1 setMovement:[[m objectForKey:@&amp;quot;movement&amp;quot;] intValue]];
                [m1 setKillMethod:[[m objectForKey:@&amp;quot;killMethod&amp;quot;] intValue]];
                [_monsters addObject:m1];
            }
        }
&lt;/pre&gt;&lt;p&gt;The new and final &lt;code&gt;-(id) init&lt;/code&gt; method should look like this.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
-(id) init {
    if( (self=[super init]) ) {
        self.isTouchEnabled = YES;
        CGSize winSize = [CCDirector sharedDirector].winSize;
        CCSprite *dirt = [CCSprite spriteWithFile:@&amp;quot;WoodRetroApple_iPad_HomeScreen.jpg&amp;quot;];
        dirt.position = ccp(winSize.width/2, winSize.height/2);
        [self addChild:dirt z:-2];
        _monsters = [[NSMutableArray alloc] init];
        // plist reading
        NSString * plistPath = [[NSBundle mainBundle] pathForResource:@&amp;quot;Enemy&amp;quot; ofType:@&amp;quot;plist&amp;quot;];
        NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] initWithContentsOfFile:plistPath];
        // load monster information from pList
        if ([dictionary objectForKey:@&amp;quot;Monsters&amp;quot; ] != nil ){
            NSMutableArray *array = [dictionary objectForKey:@&amp;quot;Monsters&amp;quot;];
            for(int i = 0; i &amp;lt; [array count]; i++){
                NSMutableDictionary *m = [array objectAtIndex:i];
                Monster *m1 = [[Monster alloc] init];
                [m1 setTag:(i+1)];
                [m1 setMonsterSprite:[[NSString alloc] initWithString:[m objectForKey:@&amp;quot;monsterSprite&amp;quot;]]];
                [m1 setSplashSprite:[[NSString alloc] initWithString:[m objectForKey:@&amp;quot;splashSprite&amp;quot;]]];
                [m1 setMinVelocity:[[m objectForKey:@&amp;quot;minVelocity&amp;quot;] floatValue]];
                [m1 setMaxVelocity:[[m objectForKey:@&amp;quot;maxVelocity&amp;quot;] floatValue]];
                [m1 setMovement:[[m objectForKey:@&amp;quot;movement&amp;quot;] intValue]];
                [m1 setKillMethod:[[m objectForKey:@&amp;quot;killMethod&amp;quot;] intValue]];
                [_monsters addObject:m1];
            }
        }
        lives = 3;
        hearthArray = [[NSMutableArray alloc] init];
        for(NSInteger i = 0; i lives; i++){
            CCSprite *hearth = [CCSprite spriteWithFile:@&amp;quot;hearth.png&amp;quot;];
            [hearthArray insertObject:hearth atIndex:i];
            hearth.position = ccp( ((i+1)*50), winSize.height - 50);
            [self addChild:hearth];
        }
        CCMenuItem *pauseButton = [CCMenuItemImage itemFromNormalImage:@&amp;quot;pauseButton.png&amp;quot; selectedImage:@&amp;quot;pauseButton.png&amp;quot; target:self selector:@selector(plusMinusButtonTapped:)];
        pauseButton.position = ccp(winSize.width - 50 , winSize.height - 50 );
        pauseMenu = [CCMenu menuWithItems:pauseButton, nil];
        pauseMenu.position = CGPointZero;
        [self addChild:pauseMenu];
        [self schedule:@selector(addMonster:) interval:0.5];
        _monstersOnScreen = [[NSMutableArray alloc] init];
        defaults = [NSUserDefaults standardUserDefaults];
        int soundDefault = [defaults integerForKey:@&amp;quot;sound&amp;quot;];
        if (soundDefault == 1) {
            [[SimpleAudioEngine sharedEngine] playBackgroundMusic:@&amp;quot;backgroundSound.caf&amp;quot;];
            [[SimpleAudioEngine sharedEngine] setEffectsVolume:0.4f];
        }
    }
    return self;
}
&lt;/pre&gt;&lt;p&gt;Note that the plists should be used over other storage methods, since iOS is optimized to read, write, and process them.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;5.&lt;/span&gt; Pause and Resume&lt;/h2&gt;&lt;p&gt;The pause and resume options are two very important options, since the game will not always be running. The correct pause and resume will save battery life and make your code performance-oriented.&lt;/p&gt;&lt;p&gt;The first step is to add another class called &lt;code&gt;PausedScene&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;.h&lt;/code&gt; should look like:&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
#import &amp;lt;Foundation/Foundation.h&amp;gt;
#import &amp;quot;cocos2d.h&amp;quot;
@interface PausedScene : CCScene {
}
+(CCScene *) scene;
@end
&lt;/pre&gt;&lt;p&gt;while the implementation will look like:&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
#import &amp;quot;PausedScene.h&amp;quot;
#import &amp;quot;MonsterRun.h&amp;quot;
#import &amp;quot;HelloWorldLayer.h&amp;quot;
@implementation PausedScene
+(CCScene *) scene {
    CCScene *scene = [CCScene node];
    PausedScene *layer = [PausedScene node];
    [scene addChild: layer];
    return scene;
}
-(id) init {
    if( (self=[super init]) ) {
        CGSize winSize = [CCDirector sharedDirector].winSize;
        CCSprite *background = [CCSprite spriteWithFile:@&amp;quot;WoodRetroApple_iPad_HomeScreen.jpg&amp;quot;];
        background.position = ccp(winSize.width/2, winSize.height/2);
        [self addChild:background z:-2];
        CCSprite *logo = [CCSprite spriteWithFile:@&amp;quot;MonsterSmashing.png&amp;quot;];
        logo.scale = 1.2;
        logo.position =  ccp(winSize.width /2 , 800 );
        [self addChild: logo];
        CCMenuItem *resumeGameButtonImage = [CCMenuItemImage itemFromNormalImage:@&amp;quot;resume.png&amp;quot; selectedImage:@&amp;quot;resume.png&amp;quot; target:self selector:@selector(onStartGamePressed)];
        CCMenuItem *exitGameButtonImage = [CCMenuItemImage itemFromNormalImage:@&amp;quot;exit.png&amp;quot; selectedImage:@&amp;quot;exit.png&amp;quot; target:self selector:@selector(mainMenuPressed)];
        CCMenu *menu = [CCMenu menuWithItems:resumeGameButtonImage,exitGameButtonImage, nil];
        menu.position = ccp(winSize.width * 0.5f, winSize.height * 0.4f);
        [menu alignItemsVerticallyWithPadding:15];
        [self addChild:menu];
    }
    return self;
}
- (void) mainMenuPressed{
    CCScene *menuScene = [HelloWorldLayer scene];
    [[CCDirector sharedDirector] replaceScene:menuScene];
}
- (void)onStartGamePressed {
    [[CCDirector sharedDirector] popScene];
}
- (void) dealloc {
    [super dealloc];
}
@end
&lt;/pre&gt;&lt;p&gt;At this point, the code should be self-explanatory with the exception of the &lt;code&gt;- (void)onStartGamePressed&lt;/code&gt; method. That method is fairly simple, however. It will &amp;#8220;pop&amp;#8221; away a screen and make the last screen visible.&lt;/p&gt;&lt;p&gt;In &lt;code&gt;MonsterRun.h&lt;/code&gt;, add the &lt;code&gt;CCMenu *pauseMenu;&lt;/code&gt; property. The &lt;code&gt;MonsterRun.m&lt;/code&gt; code is now complete, so we&amp;#8217;ll look at the following lines.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
    CCMenuItem *pauseButton = [CCMenuItemImage itemFromNormalImage:@&amp;quot;pauseButton.png&amp;quot; selectedImage:@&amp;quot;pauseButton.png&amp;quot; target:self selector:@selector(plusMinusButtonTapped:)];
    pauseButton.position = ccp(winSize.width - 50 , winSize.height - 50 );
    pauseMenu = [CCMenu menuWithItems:pauseButton, nil];
    pauseMenu.position = CGPointZero;
&lt;/pre&gt;&lt;p&gt;The method codes mean that for a given &lt;code&gt;CCMenuItem&lt;/code&gt;, we&amp;#8217;ll add an image (available in the resources), a selector, and a position.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;- (void)plusMinusButtonTapped&lt;/code&gt; method is called every time the pause menu is touched. If the game is not paused, it will &amp;#8220;push&amp;#8221; a new scene, the &lt;strong&gt;PauseScene&lt;/strong&gt;, onscreen and pause the game. If the game is paused, it&amp;#8217;ll resume the animation and verify if it can start sound-checking the user defaults.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
- (void)plusMinusButtonTapped:(id)sender {
    if(![[CCDirector sharedDirector] isPaused]){
        [self pauseSchedulerAndActions];
        CCScene *menuScene = [PausedScene scene];
        [[CCDirector sharedDirector] pushScene:menuScene];
    }
    else{
        [[CCDirector sharedDirector] stopAnimation];
        [[CCDirector sharedDirector] resume];
        [[CCDirector sharedDirector] startAnimation];
        int soundDefault = [defaults integerForKey:@&amp;quot;sound&amp;quot;];
        if (soundDefault == 1)
            [[SimpleAudioEngine sharedEngine] resumeBackgroundMusic];
    }
}
&lt;/pre&gt;&lt;p&gt;The next image presents the pause menu with two options, resume and exit. Resume will bring the player back to the game board, whilst exit will take the user back to the main menu.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Cocos2D-Tutorial_Part-Three_3.png" alt="Figure 3: Pause menu" /&gt;&lt;/p&gt; &lt;figcaption&gt;Illustration of the pause menu.&lt;/figcaption&gt; &lt;/figure&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;6.&lt;/span&gt; Results&lt;/h2&gt;&lt;p&gt;The next image presents the final version of the gameplay interface.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Cocos2D-Tutorial_Part-Three_4.png" alt="Figure 4: Gameplay" /&gt;&lt;/p&gt; &lt;figcaption&gt;Illustration of gameplay.&lt;/figcaption&gt; &lt;/figure&gt;&lt;p&gt;The next image presents the final version of the main menu.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Cocos2D-Tutorial_Part-Three_5.png" alt="Figure 5: Main menu" /&gt;&lt;/p&gt; &lt;figcaption&gt;Illustration of the Main menu.&lt;/figcaption&gt; &lt;/figure&gt;&lt;p&gt;At this point, you should be able to understand and perform the following tasks:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Add custom labels.&lt;/li&gt;&lt;li&gt;Use, define and add the particle system.&lt;/li&gt;&lt;li&gt;Add custom sound and background music.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;NSUserDefaults&lt;/strong&gt; and &lt;strong&gt;SimpleAudioEngine&lt;/strong&gt; knowledge&lt;/li&gt;&lt;li&gt;Use simple or advanced plists.&lt;/li&gt;&lt;li&gt;Pause and resume Cocos2D mechanisms.&lt;/li&gt;&lt;li&gt;Know how to create a game.&lt;/li&gt;&lt;/ul&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;7.&lt;/span&gt; Notes&lt;/h2&gt;&lt;p&gt;The authors have done additional work, which is summarized below:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Custom background.&lt;/li&gt;&lt;li&gt;Customization of application icon (using Apple guidelines).&lt;/li&gt;&lt;li&gt;Changing the application name that appears on the device or emulator, eliminating the dots in the name if that name is too long.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;This concludes the third and final tutorial demonstrating how to create a Monster Smasher game using Cocos2D. By now, you should have enough knowledge to create a simple Cocos2D game using the same game engine. If you have any questions or comments, please feel free to leave them in the comments section here.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MobileTuts/~4/OFzjhPbQzAE" height="1" width="1"/&gt;</description> <wfw:commentRss>http://mobile.tutsplus.com/tutorials/iphone/build-a-monster-smashing-game-with-cocos2d-sound-game-mechanics/feed/</wfw:commentRss> <slash:comments>0</slash:comments> <feedburner:origLink>http://mobile.tutsplus.com/tutorials/iphone/build-a-monster-smashing-game-with-cocos2d-sound-game-mechanics/</feedburner:origLink></item> <item><title>Tuts+ Jobs is now free!</title><link>http://feedproxy.google.com/~r/MobileTuts/~3/ns4iwIhVTtg/</link> <comments>http://mobile.tutsplus.com/articles/news/tuts-jobs-is-now-free/#comments</comments> <pubDate>Mon, 17 Jun 2013 18:11:23 +0000</pubDate> <dc:creator>Joel Bankhead</dc:creator> <category><![CDATA[News]]></category> <guid isPermaLink="false">http://mobile.tutsplus.com/?p=18039</guid> <description>&lt;p&gt;&lt;strong&gt;Our awesome &lt;a
href="https://jobs.tutsplus.com/"&gt;new job board&lt;/a&gt; is now free and full of enticing opportunities!&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;a
href="https://jobs.tutsplus.com/"&gt;Tuts+ Jobs&lt;/a&gt; is a job board for full time, part time and casual employment opportunities for web and creative professionals. A brand new site to go alongside the &lt;a
href="http://tutsplus.com/"&gt;Tuts+ Educational Network&lt;/a&gt; and the &lt;a
href="http://themeforest.net/"&gt;Envato Marketplaces&lt;/a&gt;, all run by &lt;a
href="http://envato.com/"&gt;Envato&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;There&amp;#8217;s no need to sign up to apply for jobs, and it&amp;#8217;s now free to post a job &amp;#8211; &lt;a
href="https://jobs.tutsplus.com/"&gt;try it now&lt;/a&gt;!&lt;br
/&gt;&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Earn and Learn&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Envato is committed to helping people earn and learn online.&lt;/strong&gt; We provide a wealth of educational material through Tuts+ and Tuts+ Premium, alongside the Envato Marketplaces to help you benefit from the creative skills you learn.&lt;/p&gt;&lt;p&gt;&lt;a
href="https://jobs.tutsplus.com/"&gt;Tuts+ Jobs&lt;/a&gt; furthers this vision perfectly. With Tuts+ you can learn the skills you need to become a creative professional, and with Tuts+ Jobs you can find an amazing job that uses those skills. Our goal here is to take the hassle out of finding a job, so we&amp;#8217;ve made the process as simple as can be!&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;a
href="http://net.tutsplus.com/?attachment_id=32578" rel="attachment wp-att-32578"&gt;&lt;img
src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/06/600.png" alt="600" width="600" height="189" class="alignnone size-full wp-image-32578" /&gt;&lt;/a&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;hr
/&gt;&lt;h2&gt;Finding a Job&lt;/h2&gt;&lt;p&gt;With &lt;a
href="https://jobs.tutsplus.com/"&gt;Tuts+ Jobs&lt;/a&gt; we&amp;#8217;re committed to making every step of the job-finding process more intuitive, simpler and more efficient. We don&amp;#8217;t want to stand between you and a great opportunity.&lt;/p&gt;&lt;p&gt;It&amp;#8217;s totally free to sign up and start applying for jobs, and if nothing matches your initial search you can receive notifications when jobs come up that match your criteria. We will have full time, part time and casual listings from all around the world. Check the listing to find out where the job is based, as some jobs may offer remote opportunities.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;a
href="http://net.tutsplus.com/?attachment_id=32590" rel="attachment wp-att-32590"&gt;&lt;img
src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/06/2.jpg" alt="2" width="600" height="353" class="alignnone size-full wp-image-32590" /&gt;&lt;/a&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;hr
/&gt;&lt;h2&gt;Posting a Job&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Posting a job is now free!&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;If you have a position that you need to fill, or a great part/full-time opportunity, then Tuts+ Jobs is the best way to find a talented and creative individual to do that job. Each 30-day listing is completely free, regardless of the type of job you&amp;#8217;re posting.&lt;/p&gt;&lt;p&gt;Your job listing will be promoted across the entire Tuts+ network. With exposure to our ten million visitors over the course of 30 days, it&amp;#8217;s a brilliant way to reach exactly the type of audience you&amp;#8217;re looking for.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Sign Up, Explore, and Subscribe&lt;/h2&gt;&lt;p&gt;There are lots of great opportunities already on Tuts+ Jobs, and we&amp;#8217;ll be posting even more exciting job positions over the next few weeks, so now is the best time to head over to the site and &lt;a
href="https://jobs.tutsplus.com/"&gt;subscribe to a job search&lt;/a&gt; that interests you. That way you&amp;#8217;ll be the first to know when any new listings show up that match your skill set and requirements.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;&lt;a
href="https://jobs.tutsplus.com"&gt;Check out Tuts+ Jobs&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MobileTuts/~4/ns4iwIhVTtg" height="1" width="1"/&gt;</description> <wfw:commentRss>http://mobile.tutsplus.com/articles/news/tuts-jobs-is-now-free/feed/</wfw:commentRss> <slash:comments>0</slash:comments> <feedburner:origLink>http://mobile.tutsplus.com/articles/news/tuts-jobs-is-now-free/</feedburner:origLink></item> <item><title>Create a Location-Aware Site with Sencha Touch</title><link>http://feedproxy.google.com/~r/MobileTuts/~3/EkqKEuWFzAE/</link> <comments>http://mobile.tutsplus.com/tutorials/mobile-web-apps/create-a-location-aware-site-with-sencha-touch/#comments</comments> <pubDate>Mon, 17 Jun 2013 16:22:00 +0000</pubDate> <dc:creator>Swarnendu De</dc:creator> <category><![CDATA[Mobile Web Apps]]></category> <guid isPermaLink="false">http://mobile.tutsplus.com/?p=17301</guid> <description>&lt;p&gt;This tutorial will guide you through the development of a Location-based mobile website using the Google Place search engine and Sencha Touch 2.1 . This is a two part tutorial and in this first part we&amp;#8217;ll learn how to create a project with Sencha cmd, create a cool theme using SASS/Compass, and find services close to the user&amp;#8217;s location.&lt;br
/&gt;&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Sencha-Touch-Locator-App_1.jpg" width="768" height="480" /&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;hr/&gt;&lt;h2&gt;&lt;span&gt;1.&lt;/span&gt; Google Place Search API&lt;/h2&gt;&lt;p&gt;Google provides a set of APIs for searching different services by types and user location. At the present time, Google supports a total of 96 service types. There are 30 more services that can only be retrieved via search. Google has a &lt;a
href="https://developers.google.com/places/documentation/" target="_blank"&gt;full list of them&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;To access the Places API, the primary goal is to register the application at &lt;a
href="https://code.google.com/apis/console" target="_blank"&gt;Google&amp;#8217;s API console&lt;/a&gt;. Once we authenticate, we&amp;#8217;ll get an API key which is required for each API request. Google has a &lt;a
href="https://developers.google.com/places/documentation/" target="_blank"&gt;step by step guide&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;The Google Places API uses an API key to identify your application. API keys are managed through the &lt;a
href="https://code.google.com/apis/console"&gt;Google APIs Console&lt;/a&gt;. You&amp;#8217;ll need your own API Key before you can begin using the API. To activate the Places API and create your key:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Visit the API Console at &lt;a
href="https://code.google.com/apis/console"&gt;https://code.google.com/apis/console&lt;/a&gt; and log in with your Google Account.&lt;/li&gt;&lt;li&gt;A default project called &lt;strong&gt;API Project&lt;/strong&gt; is created for you when you first log in to the API Console. You can use the project, or create a new one by clicking the &lt;strong&gt;API Project&lt;/strong&gt; button at the top of the window and selecting &lt;strong&gt;Create&lt;/strong&gt;. &lt;a
href="https://developers.google.com/maps/documentation/business"&gt;Maps API for Business&lt;/a&gt; customers must use the API project created for them as part of their Places for Business purchase.&lt;/li&gt;&lt;li&gt;Click the &lt;strong&gt;Services&lt;/strong&gt; link from the left-hand menu.&lt;/li&gt;&lt;li&gt;Click the &lt;strong&gt;Status&lt;/strong&gt; switch next to the &lt;strong&gt;Places API&lt;/strong&gt; entry. The switch slides to &lt;strong&gt;On&lt;/strong&gt;.&lt;/li&gt;&lt;li&gt;Click &lt;strong&gt;API access&lt;/strong&gt; from the left navigation. Your key is listed in the &lt;strong&gt;Simple API Access&lt;/strong&gt; section.&lt;/li&gt;&lt;/ol&gt;&lt;hr/&gt;&lt;h2&gt;&lt;span&gt;2.&lt;/span&gt; Create and Structure the App&lt;/h2&gt;&lt;p&gt;I&amp;#8217;m assuming that you&amp;#8217;ve got a local server and Sencha setup is done. If not, please go through the detail documentation here with all the steps. We generate the Locator app using this command inside our local server.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
sencha -sdk /path/to/sdk generate app Locator c:/xampp/htdocs/locator
&lt;/pre&gt;&lt;p&gt;Once we&amp;#8217;re done, we&amp;#8217;ll open the app in the browser with the url &lt;strong&gt;http://localhost/locator&lt;/strong&gt; and see a basic tabbed application.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Sencha-Touch-Locator-App_2.png" width="263px;" height="395px;" /&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;p&gt;Now we need to structure the app with the MVC components.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Controllers&lt;/strong&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;App.js&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;strong&gt;Views&lt;/strong&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Main.js&lt;/li&gt;&lt;li&gt;Categories.js&lt;/li&gt;&lt;li&gt;PlaceList.js&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;strong&gt;Stores&lt;/strong&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Categories.js&lt;/li&gt;&lt;li&gt;Places.js&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;&lt;strong&gt;Models&lt;/strong&gt;&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Category&lt;/li&gt;&lt;li&gt;Place&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;A Sencha application can have multiple controller files. However, for a small application like this, one controller will be okay. We&amp;#8217;ll keep all the event&amp;#8217;s bindings and related functionality inside this controller.&lt;/p&gt;&lt;p&gt;The views represent the pages of the application.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Main view&lt;/strong&gt; works like a parent of all the views.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Categories&lt;/strong&gt; will list all the services Google supports.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;PlaceList view&lt;/strong&gt; will show a list of all the places near the user&amp;#8217;s location and based on a particular service.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Since we have two lists, we maintain two models: &lt;strong&gt;Category&lt;/strong&gt; and &lt;strong&gt;Place&lt;/strong&gt;. Similarly, two storage &lt;strong&gt;Categories&lt;/strong&gt; and &lt;strong&gt;Places&lt;/strong&gt; are needed for retrieving and saving related data. We need to add all these component details in &lt;strong&gt;app.js&lt;/strong&gt; so that the Sencha engine can load them up on start.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
Ext.Loader.setPath({
  'Ext': 'touch/src',
  'Locator': 'app'
});
Ext.application({
  name: 'Locator',
  requires: [
    'Ext.MessageBox',
    'Locator.util.Util'],
  views: [
    'Main',
    'Categories',
    'PlaceList'],
  controllers: ['App'],
  models: ['Category', 'Place'],
  stores: ['Categories', 'Places'],
  icon: {
    '57': 'resources/icons/Icon.png',
    '72': 'resources/icons/Icon~ipad.png',
    '114': 'resources/icons/Icon@2x.png',
    '144': 'resources/icons/Icon~ipad@2x.png'
  },
  isIconPrecomposed: true,
  startupImage: {
    '320x460': 'resources/startup/320x460.jpg',
    '640x920': 'resources/startup/640x920.png',
    '768x1004': 'resources/startup/768x1004.png',
    '748x1024': 'resources/startup/748x1024.png',
    '1536x2008': 'resources/startup/1536x2008.png',
    '1496x2048': 'resources/startup/1496x2048.png'
  },
  launch: function () {
    // Destroy the #appLoadingIndicator element
    Ext.fly('appLoadingIndicator').destroy();
    // Initialize the main view
    Ext.Viewport.add(Ext.create('Locator.view.Main'));
  },
  onUpdated: function () {
    Ext.Msg.confirm(
      &amp;quot;Application Update&amp;quot;,
      &amp;quot;This application has just successfully been updated to the latest version. Reload now?&amp;quot;,
    function (buttonId) {
      if (buttonId === 'yes') {
        window.location.reload();
      }
    });
  }
});
&lt;/pre&gt;&lt;hr/&gt;&lt;h2&gt;&lt;span&gt;3.&lt;/span&gt; Common Functions&lt;/h2&gt;&lt;p&gt;For every application, we need a set of common functions and properties that will be used throughout the application. We create a Util singleton class for the same thing and put the file under the &lt;strong&gt;app/util/&lt;/strong&gt; directory. You do not need to understand the functions of this file at present. We&amp;#8217;ll keep discussing these functions as we move forward.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
Ext.define('Locator.util.Util', {
  singleton: true,
  // Whether the application views will have a animation while changing on=r not
  enablePageAnimations: true,
  // User's current location is saved here
  userLocation: null,
  // Google place api key
  API_KEY: 'AIzaSyBmbmtQnXfq22RJhJfitKao60wDgqrC5gA',
  // All the api urls
  api: (function () {
    //var baseUrl = 'https://maps.googleapis.com/maps/api/place/';
    var baseUrl = 'php/action.php';
    return {
      baseUrl: baseUrl,
      categories: 'resources/data/categories.json',
      nearestPlaces: baseUrl + '',
      nearBySearch: 'nearbysearch',
      photo: 'photo',
      details: 'details'
    }
  })(),
  // Destroy a Sencha view
  destroyCmp: function (child, parent) {
    parent = parent || Ext.Viewport;
    if (child) {
      Ext.defer(function () {
        parent.remove(child);
      }, Locator.util.Util.animDuration);
    }
  },
  // Show general message alert
  showMsg: function (msg, title, cb, scope) {
    if (msg) {
      Ext.Msg.alert(title || 'Error', msg.toString(), cb || function () {}, scope || window);
    }
    return this;
  },
  // Animate the active item
  showActiveItem: function (parentPanel, childPanel, animation) {
    animation = Ext.apply({
      type: 'slide',
      duration: LocatrConfig.amimationDuration
    }, animation || {});
    if (parentPanel &amp;amp;amp; amp; &amp;amp;amp; amp; childPanel) {
      if (this.enablePageAnimations &amp;amp;amp; amp; &amp;amp;amp; amp; animation &amp;amp;amp; amp; &amp;amp;amp; amp; animation.type) {
        parentPanel.animateActiveItem(childPanel, animation);
      } else {
        parentPanel.setActiveItem(childPanel);
      }
    }
    return this;
  },
  // Show a loading box on a
  showLoading: function (panel, doShow, message) {
    panel = panel || Ext.Viewport;
    if (panel) {
      if (doShow) {
        panel.setMasked({
          xtype: 'loadmask',
          message: message || 'Loading...'
        });
      } else {
        panel.setMasked(false);
      }
    }
    return this;
  },
  // Capitalize first character of each word of a string
  toTitleCase: function (str) {
    if (!str) {
      return '';
    }
    return str.replace(/\w\S*/g, function (txt) {
      return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
    });
  }
});
&lt;/pre&gt;&lt;hr/&gt;&lt;h2&gt;&lt;span&gt;4.&lt;/span&gt; Categories List&lt;/h2&gt;&lt;p&gt;We set up the &lt;strong&gt;Main&lt;/strong&gt; view, which is the wrapper of all the views. We use &lt;strong&gt;Navigation&lt;/strong&gt; View for the same thing, which is pretty useful for simple Card layout and back button management. At launch, it only has the categories list as its child.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
/**
 * Main view - holder of all the views.
 * Card layout by default in order to support multiple views as items
 */
Ext.define('Locator.view.Main', {
  extend: 'Ext.NavigationView',
  xtype: 'main',
  config: {
    cls: 'default-bg',
    items: [{
      xtype: 'categories'
    }]
  }
});
&lt;/pre&gt;&lt;p&gt;Now application setup is done. We have the Google Places API key and we&amp;#8217;re ready to create a list of all the types and show it in the home page. There&amp;#8217;s a problem, though. Google doesn&amp;#8217;t provide an API for retrieving all these types. We have to manually create a data file listing all the types. I&amp;#8217;ve created a &lt;strong&gt;json&lt;/strong&gt; file named &lt;strong&gt;categories.json&lt;/strong&gt; listing all the available types, and put it inside the &lt;strong&gt;resources/data&lt;/strong&gt; directory.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
{categories:[{type:&amp;quot;accounting&amp;quot;},{type:&amp;quot;airport&amp;quot;},{type:&amp;quot;amusement_park&amp;quot;},{type:&amp;quot;aquarium&amp;quot;},{type:&amp;quot;art_gallery&amp;quot;},{type:&amp;quot;atm&amp;quot;},{type:&amp;quot;bakery&amp;quot;},{type:&amp;quot;bank&amp;quot;},{type:&amp;quot;bar&amp;quot;},{type:&amp;quot;beauty_salon&amp;quot;},{type:&amp;quot;bicycle_store&amp;quot;},{type:&amp;quot;book_store&amp;quot;},{type:&amp;quot;bowling_alley&amp;quot;},{type:&amp;quot;bus_station&amp;quot;},{type:&amp;quot;cafe&amp;quot;},{type:&amp;quot;campground&amp;quot;},{type:&amp;quot;car_dealer&amp;quot;},{type:&amp;quot;car_rental&amp;quot;},{type:&amp;quot;car_repair&amp;quot;},{type:&amp;quot;car_wash&amp;quot;},{type:&amp;quot;casino&amp;quot;},{type:&amp;quot;cemetery&amp;quot;},{type:&amp;quot;church&amp;quot;},{type:&amp;quot;city_hall&amp;quot;},{type:&amp;quot;clothing_store&amp;quot;},{type:&amp;quot;convenience_store&amp;quot;},{type:&amp;quot;courthouse&amp;quot;},{type:&amp;quot;dentist&amp;quot;},{type:&amp;quot;department_store&amp;quot;},{type:&amp;quot;doctor&amp;quot;},{type:&amp;quot;electrician&amp;quot;},{type:&amp;quot;electronics_store&amp;quot;},{type:&amp;quot;embassy&amp;quot;},{type:&amp;quot;establishment&amp;quot;},{type:&amp;quot;finance&amp;quot;},{type:&amp;quot;fire_station&amp;quot;},{type:&amp;quot;florist&amp;quot;},{type:&amp;quot;food&amp;quot;},{type:&amp;quot;funeral_home&amp;quot;},{type:&amp;quot;furniture_store&amp;quot;},{type:&amp;quot;gas_station&amp;quot;},{type:&amp;quot;general_contractor&amp;quot;},{type:&amp;quot;grocery_or_supermarket&amp;quot;},{type:&amp;quot;gym&amp;quot;},{type:&amp;quot;hair_care&amp;quot;},{type:&amp;quot;hardware_store&amp;quot;},{type:&amp;quot;health&amp;quot;},{type:&amp;quot;hindu_temple&amp;quot;},{type:&amp;quot;home_goods_store&amp;quot;},{type:&amp;quot;hospital&amp;quot;},{type:&amp;quot;insurance_agency&amp;quot;},{type:&amp;quot;jewelry_store&amp;quot;},{type:&amp;quot;laundry&amp;quot;},{type:&amp;quot;lawyer&amp;quot;},{type:&amp;quot;library&amp;quot;},{type:&amp;quot;liquor_store&amp;quot;},{type:&amp;quot;local_government_office&amp;quot;},{type:&amp;quot;locksmith&amp;quot;},{type:&amp;quot;lodging&amp;quot;},{type:&amp;quot;meal_delivery&amp;quot;},{type:&amp;quot;meal_takeaway&amp;quot;},{type:&amp;quot;mosque&amp;quot;},{type:&amp;quot;movie_rental&amp;quot;},{type:&amp;quot;movie_theater&amp;quot;},{type:&amp;quot;moving_company&amp;quot;},{type:&amp;quot;museum&amp;quot;},{type:&amp;quot;night_club&amp;quot;},{type:&amp;quot;painter&amp;quot;},{type:&amp;quot;park&amp;quot;},{type:&amp;quot;parking&amp;quot;},{type:&amp;quot;pet_store&amp;quot;},{type:&amp;quot;pharmacy&amp;quot;},{type:&amp;quot;physiotherapist&amp;quot;},{type:&amp;quot;place_of_worship&amp;quot;},{type:&amp;quot;plumber&amp;quot;},{type:&amp;quot;police&amp;quot;},{type:&amp;quot;post_office&amp;quot;},{type:&amp;quot;real_estate_agency&amp;quot;},{type:&amp;quot;restaurant&amp;quot;},{type:&amp;quot;roofing_contractor&amp;quot;},{type:&amp;quot;rv_park&amp;quot;},{type:&amp;quot;school&amp;quot;},{type:&amp;quot;shoe_store&amp;quot;},{type:&amp;quot;shopping_mall&amp;quot;},{type:&amp;quot;spa&amp;quot;},{type:&amp;quot;stadium&amp;quot;},{type:&amp;quot;storage&amp;quot;},{type:&amp;quot;store&amp;quot;},{type:&amp;quot;subway_station&amp;quot;},{type:&amp;quot;synagogue&amp;quot;},{type:&amp;quot;taxi_stand&amp;quot;},{type:&amp;quot;train_station&amp;quot;},{type:&amp;quot;travel_agency&amp;quot;},{type:&amp;quot;university&amp;quot;},{type:&amp;quot;veterinary_care&amp;quot;},{type:&amp;quot;zoo&amp;quot;}]}
&lt;/pre&gt;&lt;h3&gt;Category Model: Model/Category.js&lt;/h3&gt;&lt;pre class="brush: jscript; title: ;"&gt;
Ext.define('Locator.model.Category', {
  extend: 'Ext.data.Model',
  config: {
    fields: [
      &amp;quot;type&amp;quot;, {
      name: &amp;quot;name&amp;quot;,
      type: &amp;quot;string&amp;quot;,
      convert: function (v, record) {
        // Converts to title case and returns
        return Locator.util.Util.toTitleCase(record.get('type').split('_').join(' '));
      }
    }, &amp;quot;size&amp;quot;]
  }
});
&lt;/pre&gt;&lt;p&gt;The &amp;#8220;name&amp;#8221; property of this model uses the same &amp;#8220;type&amp;#8221; value of the category. Since most of the types have an &amp;#8220;underscore&amp;#8221;, this convert function creates a value omitting the &amp;#8220;_&amp;#8221; and converting the string into title case. So, &amp;#8220;travel_agency&amp;#8221; becomes &amp;#8220;&lt;strong&gt;Travel Agency&lt;/strong&gt;&amp;#8221; and we save it under the name property of this model.&lt;/p&gt;&lt;h3&gt;Categories Store: Store/Categories.js&lt;/h3&gt;&lt;pre class="brush: jscript; title: ;"&gt;
Ext.define('Locator.store.Categories', {
  extend: 'Ext.data.Store',
  config: {
    model: 'Locator.model.Category',
    autoLoad: true,
    sorters: 'name',
    grouper: {
      groupFn: function (record) {
        return record.get('name')[0];
      }
    },
    proxy: {
      type: 'ajax',
      url: Locator.util.Util.api.categories,
      reader: {
        type: 'json',
        rootProperty: 'categories'
      }
    }
  }
});
&lt;/pre&gt;&lt;p&gt;We auto-load the store because it should be the first request in the app. We use a grouper function for a grouped list, and sort by the first character of each service name.&lt;/p&gt;&lt;h3&gt;Categories View: View/Categories.js&lt;/h3&gt;&lt;p&gt;Category view is a plain list. We use indexBar and grouped functionality for easy accessing all the types.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
Ext.define('Locator.view.Categories', {
  extend: 'Ext.List',
  xtype: 'categories',
  config: {
    cls: 'default-bg category-list',
    itemTpl: '{name}',
    store: 'Categories',
    grouped: true,
    indexBar: true,
    title: Lang.home
  }
});
&lt;/pre&gt;&lt;p&gt;The list looks like this:&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Sencha-Touch-Locator-App_3.jpg" width="192" height="300" /&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;hr/&gt;&lt;h2&gt;&lt;span&gt;5.&lt;/span&gt; Tweaking the Existing Theme&lt;/h2&gt;&lt;p&gt;We can add certain sets of pre-existing variables to change the existing Sencha theme and get a new look. The following is the SASS file. If you don&amp;#8217;t have SASS setup already done, please follow &lt;a
href="http://www.sencha.com/blog/an-introduction-to-theming-sencha-touch" target="_blank"&gt;this blog post&lt;/a&gt; for a step-by-step guide.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
// Basic color definitions
$base-color: #333;
$base-gradient: 'matte';
$active-color: #36B8FF;
// Toolbar styles
$toolbar-base-color: #444;
// List styles
$list-header-bg-color : #ABE2FF;
@import 'sencha-touch/default/all';
// You may remove any of the following modules that you
// do not use in order to create a smaller css file.
@include sencha-panel;
@include sencha-buttons;
@include sencha-sheet;
@include sencha-picker;
@include sencha-tabs;
@include sencha-toolbar;
@include sencha-toolbar-forms;
@include sencha-indexbar;
@include sencha-list;
@include sencha-layout;
@include sencha-carousel;
@include sencha-form;
@include sencha-msgbox;
@include sencha-loading-spinner;
@include sencha-list-pullrefresh;
&lt;/pre&gt;&lt;p&gt;We change the top toolbar color and list header color, and add the list plugin mix-in.&lt;/p&gt;&lt;hr/&gt;&lt;h2&gt;&lt;span&gt;6.&lt;/span&gt; Geolocation and Retrieving API Data&lt;/h2&gt;&lt;p&gt;Once we click one of the category items, we&amp;#8217;ll want to view all the businesses near the user&amp;#8217;s current location in that category. We must follow this set of tasks:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Fetch user&amp;#8217;s current location using GeoLocation API&lt;/li&gt;&lt;li&gt;With the latitude and longitude, send a request to Google API to fetch the data&lt;/li&gt;&lt;li&gt;Show the place list page&lt;/li&gt;&lt;/ol&gt;&lt;h3&gt;Geolocation&lt;/h3&gt;&lt;p&gt;We can either use the navigator&amp;#8217;s &lt;a
href="http://diveintohtml5.info/geolocation.html" target="_blank"&gt;geolocation&lt;/a&gt; function directly or use Sencha&amp;#8217;s &lt;strong&gt;Ext.device.Geolocation&lt;/strong&gt;. We save the latitude and longitude in the &lt;strong&gt;Util&lt;/strong&gt; instance for future use.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
Ext.device.Geolocation.getCurrentPosition({
  success: function (position) {
    me.util.userLocation = position.coords.latitude + ',' + position.coords.longitude;
  },
  failure: function () {
    me.util.showMsg(Lang.locationRetrievalError);
  }
});
&lt;/pre&gt;&lt;h3&gt;Data Retrieval&lt;/h3&gt;&lt;p&gt;Google Places API doesn&amp;#8217;t support &lt;a
href="http://json-p.org/" target="_blank"&gt;JSONP&lt;/a&gt; requests yet, so we won&amp;#8217;t be able to retrieve the data directly from the client side. We have to use a server proxy to retrieve the data. This problem can be solved using PHP and cURL.&lt;/p&gt;&lt;p&gt;The &lt;strong&gt;Config&lt;/strong&gt; file holds a number of constants. We set the base API url, data output type, and image size details.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
define(&amp;quot;BASE_API_URL&amp;quot;, &amp;quot;https://maps.googleapis.com/maps/api/place/&amp;quot;);
define(&amp;quot;DATA_OUTPUT_TYPE&amp;quot;, &amp;quot;json&amp;quot;);
define(&amp;quot;IMAGE_MAX_HEIGHT&amp;quot;, 500);
define(&amp;quot;IMAGE_MAX_WIDTH&amp;quot;, 500);
&lt;/pre&gt;&lt;h3&gt;Locator.php&lt;/h3&gt;&lt;p&gt;This is a PhP class which holds the functionality for setting up the URL, sending cURL requests, and retrieving data.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
class Locatr {
  /**
   * Sets up the url according to passed parameters
   * @return String A complete url with all the query strings
   */
  private static function getFinalUrl() {
    return html_entity_decode(BASE_API_URL.$_REQUEST[&amp;quot;action&amp;quot;].
    &amp;quot;/&amp;quot;.DATA_OUTPUT_TYPE.
    &amp;quot;?&amp;quot;.$_SERVER['QUERY_STRING']);
  }
  /**
   * A generic function to send all the cURL requests
   * @return String Response for that cURL request
   */
  private static function sendCurlRequest() {
    // Get cURL resource
    $curl = curl_init();
    // Set some options - we are passing in a useragent too here
    curl_setopt_array($curl, array(
    CURLOPT_RETURNTRANSFER = &amp;amp;gt; 1,
    CURLOPT_URL = &amp;amp;gt; self::getFinalUrl(),
    CURLOPT_SSL_VERIFYPEER = &amp;amp;gt; false,
    CURLOPT_USERAGENT = &amp;amp;gt; 'Codular Sample cURL Request'));
    // Send the request &amp;amp;amp; save response to $resp
    $response = curl_exec($curl);
    // Close request to clear up some resources
    curl_close($curl);
    return $response;
  }
  /**
   * Retrieves all the nearby places and one image of each if available
   * @return String Returns all the places in json
   */
  public static function getNearBySearchLocations() {
    try {
      $data = json_decode(self::sendCurlRequest());
      $item = &amp;quot;&amp;quot;;
      for ($i = 0; $i &amp;amp;lt; count($data - &amp;amp;gt; results); $i++) {
        $item = $data - &amp;amp;gt; results[$i];
        if (isset($item - &amp;amp;gt; photos)) {
          $imageUrl = BASE_API_URL.
          &amp;quot;photo?photoreference=&amp;quot;.$item - &amp;amp;gt; photos[0] - &amp;amp;gt; photo_reference.
          &amp;quot;&amp;amp;amp;sensor=false&amp;amp;amp;maxheight=300&amp;amp;amp;maxwidth=300&amp;amp;amp;key=&amp;quot;.$_GET[&amp;quot;key&amp;quot;];
          $data - &amp;amp;gt; results[$i] - &amp;amp;gt; photos[0] - &amp;amp;gt; url = $imageUrl;
        }
      }
      return json_encode($data);
    } catch (Exception $e) {
      print &amp;quot;Error at getNearBySearchLocations : &amp;quot;.$e - &amp;amp;gt; getMessage();
    }
  }
}
&lt;/pre&gt;&lt;p&gt;Here&amp;#8217;s the functionality of each method in this class:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;strong&gt;getFinalUrl&lt;/strong&gt;: This sets up the complete URL with the base URL, the response data type, and the query strings sent from the client side. We call this function from the &lt;strong&gt;action.php&lt;/strong&gt; file.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;sendCurlRequest:&lt;/strong&gt; This is a basic cURL GET request for retrieving the data. You can use the &lt;code&gt;file_get_contents()&lt;/code&gt; method as well to get the data here.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;getNearBySearchLocations:&lt;/strong&gt; This fetches the data from Google API for the related type within a certain radius. However, there is a trick: Google doesn&amp;#8217;t pass the photos of a business with this data. Instead they send references to the images. You need to construct a URL with the image height, width, API key, and photo reference to get that image.&lt;p&gt;This URL is constructed with the first image reference and passed with the response data for every place. This helps us show at least one image available for every business.&lt;/p&gt;&lt;h3&gt;action.php&lt;/h3&gt;&lt;p&gt;This file is just used to call the &lt;strong&gt;getNearBySearchLocations&lt;/strong&gt; function of the Locator class. We send the ajax requests from our client side directly to this file.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
include_once 'config.php';
include_once 'Locatr.php';
$action = $_REQUEST[&amp;quot;action&amp;quot;];
if (!isset($action)) {
  throw new Exception(&amp;quot;'action' parameter is not supplied&amp;quot;);
}
switch ($action) {
  case &amp;quot;nearbysearch&amp;quot;:
    print Locatr::getNearBySearchLocations();
    break;
}
&lt;/pre&gt;&lt;hr/&gt;&lt;h2&gt;&lt;span&gt;7.&lt;/span&gt; Place List&lt;/h2&gt;&lt;p&gt;For the Place list, we need a store and a model similar to the categories list.&lt;/p&gt;&lt;h3&gt;Place Model: Model/Place&lt;/h3&gt;&lt;pre class="brush: jscript; title: ;"&gt;
Ext.define('Locator.model.Place', {
  extend: 'Ext.data.Model',
  config: {
    fields: [
      &amp;quot;formatted_address&amp;quot;,
      &amp;quot;geometry&amp;quot;,
      &amp;quot;icon&amp;quot;,
      &amp;quot;id&amp;quot;,
      &amp;quot;name&amp;quot;,
      &amp;quot;rating&amp;quot;,
      &amp;quot;reference&amp;quot;,
      &amp;quot;types&amp;quot;,
      &amp;quot;vicinity&amp;quot;,
      &amp;quot;photos&amp;quot;]
  }
});
&lt;/pre&gt;&lt;h3&gt;Places Store : Store/Places&lt;/h3&gt;&lt;pre class="brush: jscript; title: ;"&gt;
Ext.define('Locator.store.Places', {
  extend: 'Ext.data.Store',
  config: {
    model: 'Locator.model.Place',
    proxy: {
      type: 'ajax',
      url: Locator.util.Util.api.nearestPlaces,
      reader: {
        type: 'json',
        rootProperty: 'results'
      }
    }
  }
});
&lt;/pre&gt;&lt;h3&gt;Main Controller: Controller/App.js&lt;/h3&gt;&lt;p&gt;Until now, we didn&amp;#8217;t need a controller for any functionality because the category list was populated automatically by its store. Now we need the controller to handle the events. We&amp;#8217;ll list all the required components under the controller refs property.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
refs: {
  categoriesList: 'categories',
  main: 'main',
  placeList: 'placelist'
}
&lt;/pre&gt;&lt;p&gt;The list click event in controls:&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
control: {
  categoriesList: {
    itemtap: 'loadPlaces'
  }
}
&lt;/pre&gt;&lt;p&gt;When clicking on a category, we want to show the list of places available under that category. As we discussed earlier, first we&amp;#8217;ll fetch the user&amp;#8217;s current location and then, with the latitude and longitude, we&amp;#8217;ll send an ajax request to the action.php file. The controller with the &amp;#8220;&lt;strong&gt;loadPlaces&lt;/strong&gt;&amp;#8221; function looks like this:&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
Ext.define('Locator.controller.App', {
  extend: 'Ext.app.Controller',
  requires: ['Ext.device.Geolocation', 'Ext.Map'],
  util: Locator.util.Util,
  config: {
    refs: {
      categoriesList: 'categories',
      main: 'main',
      placeList: 'placelist'
    },
    control: {
      categoriesList: {
        itemtap: 'loadPlaces'
      }
    }
  },
  /**
   * Retrieve all the places for a particlur category
   */
  loadPlaces: function (list, index, target, record) {
    var me = this,
      loadPlaces = function () {
        // Show the place list page
        me.showPlaceList(record);
        // Load the store with user's location, radius, type and api key
        store.getProxy().setExtraParams({
          location: me.util.userLocation,
          action: me.util.api.nearBySearch,
          radius: me.util.defaultSearchRadius,
          sensor: false,
          key: me.util.API_KEY,
          types: record.get('type')
        });
        store.load(function (records) {
          me.util.showLoading(me.getPlaceList(), false);
        });
      },
      store = Ext.getStore('Places');
    // If user's location is already not set, fetch it.
    // Else load the places for the saved user's location
    if (!me.util.userLocation) {
      Ext.device.Geolocation.getCurrentPosition({
        success: function (position) {
          me.util.userLocation = position.coords.latitude + ',' + position.coords.longitude;
          loadPlaces();
        },
        failure: function () {
          me.util.showMsg(Lang.locationRetrievalError);
        }
      });
    } else {
      // Clean the store if there is any previous data
      store.removeAll();
      loadPlaces();
    }
  },
  /**
   * Show place list
   */
  showPlaceList: function (record) {
    this.getMain().push({
      xtype: 'placelist',
      title: record.get('name')
    });
  }
});
&lt;/pre&gt;&lt;h3&gt;Place List View: View/PlaceList&lt;/h3&gt;&lt;p&gt;The &lt;strong&gt;PlaceList&lt;/strong&gt; view is also a plain list. We use XTemplate here in order to use some filtering functions. The &lt;strong&gt;getImage&lt;/strong&gt; function receives the image of the business. If the image is not available, it returns the icon for that business.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
Ext.define('Locator.view.PlaceList', {
  extend: 'Ext.List',
  xtype: 'placelist',
  config: {
    cls: 'default-bg placelist',
    store: 'Places',
    emptyText: Lang.placeList.emptyText,
    itemTpl: Ext.create('Ext.XTemplate',
      '{[this.getImage(values)]}',
      '&amp;amp;lt;div class=&amp;quot;item&amp;quot; data-placelistitem-id=&amp;quot;{id}&amp;quot;&amp;amp;gt;',
      '&amp;amp;lt;div class=&amp;quot;name&amp;quot;&amp;amp;gt;{name}&amp;amp;lt;/div&amp;amp;gt;',
      '&amp;amp;lt;div class=&amp;quot;vicinity&amp;quot;&amp;amp;gt;{vicinity}&amp;amp;lt;/div&amp;amp;gt;',
      '{rating:this.getRating}',
      '&amp;amp;lt;/div&amp;amp;gt;', {
      // Returns the business image if available. Else shows the icon available for that business
      getImage: function (data) {
        if (data.photos &amp;amp;amp;&amp;amp;amp; data.photos.length &amp;amp;gt; 0) {
          return '&amp;amp;lt;div class=&amp;quot;photo&amp;quot;&amp;amp;gt;&amp;amp;lt;img src=&amp;quot;' + data.photos[0].url + '&amp;quot; /&amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;';
        }
        return '&amp;amp;lt;div class=&amp;quot;icon-wrapper&amp;quot;&amp;amp;gt;&amp;amp;lt;div class=&amp;quot;icon&amp;quot; style=&amp;quot;-webkit-mask-image:url(' + data.icon + ');&amp;quot; &amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;';
      },
      // Shows a star based rating. The functional details is given in the Util class
      getRating: function (rating) {
        return Locator.util.Util.getRating(rating);
      }
    })
  }
});
&lt;/pre&gt;&lt;p&gt;We get a rating from zero to five for businesses. Instead of showing the rating number, we can write a simple function to show the ratings as stars. We add the &lt;strong&gt;getRating&lt;/strong&gt; function to the &lt;strong&gt;util&lt;/strong&gt; file, which can be used inside this PlaceList template functions:&lt;/p&gt;&lt;p&gt;There are three images: no-star, half-star and full-star. The CSS is given below:&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
getRating: function (rating, max, hideRatingValue) {
  if (rating !== undefined) {
    var str = '&amp;amp;lt;div class=&amp;quot;ratings&amp;quot;&amp;amp;gt;';
    rating = parseFloat(rating);
    max = max || 5;
    // We divide the rating into a part upto maximum value
    for (var i = 1; i &amp;amp;lt; = max; i++) {
      // For each 1 rating, add a full star
      if (i &amp;amp;lt; = rating) {
        str += '&amp;amp;lt;div class=&amp;quot;star full-star&amp;quot;&amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;';
      }
      if (i &amp;amp;gt; rating) {
        // If the part rating is a decimal between 0 &amp;amp;amp; 1, add half star
        if (rating % 1 !== 0 &amp;amp;amp;&amp;amp;amp;; (i - rating) &amp;amp;lt; 1) {
          str += '&amp;amp;lt;div class=&amp;quot;star half-star&amp;quot;&amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;';
        }
        // For all part rating value 0, add no star
        else {
          str += '&amp;amp;lt;div class=&amp;quot;star no-star&amp;quot;&amp;amp;gt;&amp;amp;lt;/div&amp;amp;gt;';
        }
      }
    }
    if (!hideRatingValue) {
      str += '&amp;amp;lt;div class=&amp;quot;value&amp;quot;&amp;amp;gt;' + rating + '&amp;amp;lt;/div&amp;amp;gt;';
    }
    str += '&amp;amp;lt;/div&amp;amp;gt;';
    return str;
  }
  return Lang.noRating;
}
&lt;/pre&gt;&lt;p&gt;&lt;h3&gt;Rating CSS:&lt;/h3&gt;&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
.ratings{
    overflow: auto;
}
.ratings div.star{
    float: left;
    height: 14px;
    width: 14px;
    background-size: 12px !important;
    background-position: 50%;
}
.ratings .full-star{
    background: url(../images/full_star.png) no-repeat;
}
.ratings .half-star{
    background: url(../images/half_star.png) no-repeat;
}
.ratings .no-star{
    background: url(../images/no_star.png) no-repeat;
}
.ratings .value{
    float: left;
    font-size: 13px;
    font-weight: bold;
    margin-left: 5px;
}
&lt;/pre&gt;&lt;p&gt;Here is the final &lt;strong&gt;PlaceList&lt;/strong&gt; view.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Sencha-Touch-Locator-App_4.jpg" width="191" height="300" /&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;p&gt;&lt;h3&gt;CSS for the PlaceList Page:&lt;/h3&gt;&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
/****************************** Place List ******************************/ .placelist.x - list - emptytext {
  font - size: 14px;
  color: #fff;
  padding: 20px;
}
.x - list.placelist.x - list - item.x - dock - horizontal {
  border: 0!important;
}
.x - list.placelist.x - list - item.item {
  /*				background: rgba(255, 255, 255, 0.8);
                                    font-size: 14px;
                                    padding: 8px;*/
  /*				background: rgba(255, 255, 255, 0.8);*/
  background: -webkit - gradient(linear, left top, left bottom, color - stop(0 % , #ffffff), color - stop(47 % , #f6f6f6), color - stop(100 % , #ededed)); /* Chrome,Safari4+ */
  background: -webkit - linear - gradient(top, #ffffff 0 % , #f6f6f6 47 % , #ededed 100 % ); /* Chrome10+,Safari5.1+ */
  font - size: 14px;
  border - radius: 5px;
  padding: 8px; - webkit - box - shadow: 0 0 10px 2px rgba(0, 0, 0, 0.6);
  padding - right: 82px;
}
.x - list.placelist.x - list - item.item.name {
  font - weight: bold;
  margin: 3px 0 8px 0;
}
.x - list.placelist.x - list - item.item.vicinity {
  font - size: 12px;
  color: #222;
    margin-bottom: 10px;
}
.x-list.placelist .x-list-item .item .rating{
}
.x-list.placelist .x-list-item .photo,
.x-list.placelist .x-list-item .icon-wrapper{
    position: absolute;
    display: -webkit-box;
    -webkit-box-align: center;
    -webkit-box-pack: center;
    right: 25px;
    top: 6px;
}
.x-list.placelist .x-list-item .photo img{
    max-width: 75px;
    max-height: 63px;
    border: 2px solid white;
    -webkit-box-shadow: 0 0 5px 0px rgba(0, 0, 0, 0.5);
    background: black;
}
.x-list.placelist .x-list-item .icon-wrapper{
    background: # 960000;
  border: 2px solid white; - webkit - box - shadow: 0 0 5px 0px rgba(0, 0, 0, 0.5);
}
.x - list.placelist.x - list - item.icon {
  width: 50px;
  height: 50px;
  background: white; - webkit - mask - image: url(http: //maps.gstatic.com/mapfiles/place_api/icons/restaurant-71.png);
  -
  webkit - mask - size: 35px; - webkit - mask - repeat: no - repeat; - webkit - mask - position: 50 % ;
  }
  /****************************** Place List ENDS ******************************/
&amp;lt;/code&amp;gt;
&amp;lt;p&amp;gt;We can add a pull-to-refresh plugin to this place list. Just add the code below in the &amp;lt;strong&amp;gt;PlaceList&amp;lt;/strong&amp;gt; array config.&amp;lt;/p&amp;gt;
&amp;lt;code&amp;gt;
plugins: [{
  xclass: 'Ext.plugin.PullRefresh',
  pullRefreshText: Lang.placeList.pullToRefresh
}]&amp;lt;/pre&amp;gt;
And because we are using a dark background, we need to change the pull-to-refresh css a bit. So, add following css in locator.css file:
&amp;lt;pre lang=&amp;quot;css&amp;quot;&amp;gt;/* Pull to refresh plugin */
.x-list-pullrefresh {
  color: #fff;
}
.x-list-pullrefresh-arrow {
  -webkit - mask: center center url(data: image / png; base64, iVBORw0KGgoAAAANSUhEUgAAACgAAAA8CAYAAAAUufjgAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAjFJREFUeNrsmU8oREEYwOexdtNuKBfFwdVhCyfuysnFiXISS + 1BLopyUpKLXETkRLaUi1LK3Q2lpPbiQLnIn03a / Hm + z86Ttv0zM++bfbOar36Hbad5v535Zp7v47iuy0wOpyoEHccRHV9L9NxPkUE / bhKCOKiOSPAdn69DsJ5I8E2HYA0QJRJ8Bb50CDYRCT7pEMQD0kwk + CByUFQEW4gE73UIhoA2IsFb4ENEMCQ5MdU1IxwygpT3oKNLMGyyYFVscdhusc8tDpu + xRG7xf95BW0O2kNiV1AgIvaQ2BzUJNgJNJYZGyUU7OG1cal4Bi68oqkDPszy2teEwJp5Cdyu / lZ1g8CwIYJ7wEF + 2YmrNw90Byx3BizgKhaqizEP1wg7CLLxCEzy / CtauMeBlQDyEfNuGrgU6SyM8F9SyVgHdmRaH6tAb4XkToEp2d4M5mOK0TWMigU2koa8vJMRZPxEb2ss2LEVPMpPLlMRxBgDZjQJLgNbxb6Uab9tAn3EcifAeKkBMoLY + j0GWonk7oB + lmsFkwhidAGHBPmIeTcAnJcbKCuIMQEs + hScAzZEBqoIYuzyFVCJI36lMJ2CDfxibZeUu + EX / 4uMIFP8ZyLejxkgK0hG5a8kP4IYSZbr1IuQVHmAX0HGX4VuGfZVJ6cQxPd1uoRcWqDW0SroFVzZAnJZ / h0LWhAjUUAw4XdSSsH8fExRTEgtGAOuOTETBb16Jk412e + bxOSwglYw6PgWYABvLk8P7zGJFwAAAABJRU5ErkJggg == ) no - repeat;
  background: #fff;
}
&lt;/pre&gt;&lt;p&gt;Here it goes:&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Sencha-Touch-Locator-App_5.png" width="192" height="300" /&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;hr/&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;This is the first part of the tutorial. We created a list of services provided by the Google Places API and then for a particular service, and we showed a list of all the nearby places. In the next and final part of this tutorial, we&amp;#8217;ll cover the following functionality:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;Showing all the places for a category in Google Maps&lt;/li&gt;&lt;li&gt;Showing the details of each place. This will include showing an individual map for a certain place, creating a mosaic Sencha-based photo gallery, a full screen image carousel, and a list of reviews.&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Sencha is at present one of the strongest HTML5-based mobile libraries. Once you set it up, you&amp;#8217;ll be able to write great, smooth mobile applications. These applications can either be used as mobile websites or can be wrapped in Phonegap to create iOS and Android hybrid apps.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MobileTuts/~4/EkqKEuWFzAE" height="1" width="1"/&gt;</description> <wfw:commentRss>http://mobile.tutsplus.com/tutorials/mobile-web-apps/create-a-location-aware-site-with-sencha-touch/feed/</wfw:commentRss> <slash:comments>2</slash:comments> <feedburner:origLink>http://mobile.tutsplus.com/tutorials/mobile-web-apps/create-a-location-aware-site-with-sencha-touch/</feedburner:origLink></item> <item><title>Android SDK: Create a Book Scanning App</title><link>http://feedproxy.google.com/~r/MobileTuts/~3/huyZnOySdhU/</link> <comments>http://mobile.tutsplus.com/tutorials/android/android-sdk-create-a-book-scanning-app/#comments</comments> <pubDate>Fri, 14 Jun 2013 18:20:05 +0000</pubDate> <dc:creator>Sue Smith</dc:creator> <category><![CDATA[Android SDK]]></category> <category><![CDATA[android]]></category> <guid isPermaLink="false">http://mobile.tutsplus.com/?p=17634</guid> <description>&lt;p&gt;With the ZXing library, you can create Android applications with barcode scanning functionality. In &lt;a
href="http://mobile.tutsplus.com/tutorials/android/android-sdk-create-a-barcode-reader/"&gt;Android SDK: Create a Barcode Reader&lt;/a&gt;, we implemented basic barcode reading with the library in a simple app. In this tutorial series, we will build on what we learned to create an app that will scan books and retrieve related information about them from Google Books API.&lt;br
/&gt;&lt;/p&gt;&lt;p&gt; Here is a preview of the app we are working toward:&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/book_scanner_final.png" alt="Book Scanner App" /&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;p&gt; This series on Creating a Book Scanner App will be in three parts:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a
href="http://mobile.tutsplus.com/?p=17634"&gt;Google Books API and ZXing Setup&lt;/a&gt;&lt;/li&gt;&lt;li&gt;User Interface Creation and Book Search (Pending Publication)&lt;/li&gt;&lt;li&gt;Retrieving and Displaying Book Information  (Pending Publication)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt; In this first part of the series, we will get the app set up for scanning &amp;#8211; you will be able to use most of the code from the previous tutorial, with any changes necessary outlined below. We will also get setup for accessing Google Books API. In the second part we will create the rest of the user interface and carry out a book search via Google Books API. In the final part we will retrieve the results of the book search and present them within the interface.&lt;/p&gt;&lt;p&gt; When the app runs, the user will be able to scan books on clicking a button. When the app receives the scan result, it will check that the format is EAN. If it is, the app will build a search query for Google Books which it will attempt to execute. When the app receives the JSON book search results, it will pick particular details out and display them within the interface. We will use two inner &lt;em&gt;AsyncTask&lt;/em&gt; classes, one for retrieving the book search results and one for retrieving an image thumbnail of the book, if one is available. We will also create a second class with a Web View in it, in which we will use the Embedded Viewer API to display a preview of the scanned book, again if one is available. We will use an asset file for the Web View, and will provide a link to the Web page for the book on Google Books site. The final app will also include steps to preserve the data displayed on state changes.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;1.&lt;/span&gt; Create a Scanner Project&lt;/h2&gt;&lt;h3&gt;Step 1&lt;/h3&gt;&lt;p&gt; If you have not already completed the previous tutorial &lt;a
href="http://mobile.tutsplus.com/tutorials/android/android-sdk-create-a-barcode-reader/"&gt;Android SDK: Create a Barcode Reader&lt;/a&gt;, you may wish to do so first. If you did complete that tutorial, you can either create a new app for this tutorial or amend the code in the scanner app you already created. We will not be explaining the functionality outlined in that first tutorial again but will run through the code necessary for the book scanning app.&lt;/p&gt;&lt;p&gt; If you are working with the app you created during the previous tutorial you may be able to omit some of the steps below &amp;#8211; just read through them and make sure you have the code outlined. We will be using the scan button as before, but do not need the two Text Views we created for that app as we will be using different views to display the book info &amp;#8211; you can leave most of the Activity class the way it is, but should replace your XML layout file content with the code indicated below.&lt;/p&gt;&lt;p&gt; If you are creating a new Android Project, let Eclipse create a blank Activity plus layout for you. Create a second package in your project for the ZXing classes as we did in the previous tutorial, giving the package the name &amp;#8220;com.google.zxing.integration.android&amp;#8221; and copying the two scanning via Intent classes into it. In your main Activity class, add the following import statements (omitting any Eclipse has already added):&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;
&lt;/pre&gt;&lt;p&gt; We will be adding code to the main Activity class later in this tutorial and throughout the series, as well as creating a second class and adding to some resource files including the layout. For the moment a new blank Activity class should contain the default content, setting the layout file created when Eclipse created the project:&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.activity_main);
}
&lt;/pre&gt;&lt;h3&gt;Step 2&lt;/h3&gt;&lt;p&gt; Let&amp;#8217;s start getting our user interface set up. Open your layout file and replace the content with the following Relative Layout contained within a Scroll View:&lt;/p&gt;&lt;pre class="brush: xml; title: ;"&gt;
&amp;lt;ScrollView xmlns:android=&amp;quot;http://schemas.android.com/apk/res/android&amp;quot;
	android:layout_width=&amp;quot;fill_parent&amp;quot;
	android:layout_height=&amp;quot;fill_parent&amp;quot;
	android:background=&amp;quot;#ffffffff&amp;quot; &amp;gt;
	&amp;lt;RelativeLayout
		android:layout_width=&amp;quot;match_parent&amp;quot;
		android:layout_height=&amp;quot;wrap_content&amp;quot;
		android:padding=&amp;quot;10dp&amp;quot; &amp;gt;
	&amp;lt;/RelativeLayout&amp;gt;
&amp;lt;/ScrollView&amp;gt;
&lt;/pre&gt;&lt;p&gt; Inside the Relative Layout, add a Button for scanning as we did in the previous tutorial:&lt;/p&gt;&lt;pre class="brush: xml; title: ;"&gt;
&amp;lt;Button android:id=&amp;quot;@+id/scan_button&amp;quot;
	android:layout_width=&amp;quot;wrap_content&amp;quot;
	android:layout_height=&amp;quot;wrap_content&amp;quot;
	android:layout_centerHorizontal=&amp;quot;true&amp;quot;
	android:padding=&amp;quot;10dp&amp;quot;
	android:background=&amp;quot;#ff333333&amp;quot;
	android:textColor=&amp;quot;#ffcccccc&amp;quot;
	android:text=&amp;quot;@string/scan&amp;quot;
	/&amp;gt;
&lt;/pre&gt;&lt;p&gt; Add the specified string to your &amp;#8220;res/values/strings&amp;#8221; XML file:&lt;/p&gt;&lt;pre class="brush: xml; title: ;"&gt;
&amp;lt;string name=&amp;quot;scan&amp;quot;&amp;gt;Scan a Book&amp;lt;/string&amp;gt;
&lt;/pre&gt;&lt;h3&gt;Step 3&lt;/h3&gt;&lt;p&gt; Let&amp;#8217;s turn to the Activity class. If you are working with the code you created for the previous scanning tutorial, you can remove all lines referencing the two Text Views we used in the Activity (&lt;em&gt;formatTxt&lt;/em&gt; and &lt;em&gt;contentTxt&lt;/em&gt;). Otherwise you can leave the Activity as it was when you completed that tutorial.&lt;/p&gt;&lt;p&gt; If you are creating the app from scratch, extend the opening Activity declaration line to implement the click listener interface:&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
public class MainActivity extends Activity implements OnClickListener
&lt;/pre&gt;&lt;p&gt; Add the outline of the &lt;em&gt;onClick&lt;/em&gt; method to your class:&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
public void onClick(View v){
//handle clicks
}
&lt;/pre&gt;&lt;p&gt; At the top of the class declaration, before &lt;em&gt;onCreate&lt;/em&gt;, add an instance variable for the scan button:&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
private Button scanBtn;
&lt;/pre&gt;&lt;p&gt; Inside &lt;em&gt;onCreate&lt;/em&gt;, retrieve a reference to the button after the existing code:&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
scanBtn = (Button)findViewById(R.id.scan_button);
scanBtn.setOnClickListener(this);
&lt;/pre&gt;&lt;h3&gt;Step 4&lt;/h3&gt;&lt;p&gt; Let&amp;#8217;s initiate scanning when the user presses the button, as we did last time. In the &lt;em&gt;onClick&lt;/em&gt; method, check for clicks on the scan button:&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
if(v.getId()==R.id.scan_button){
	IntentIntegrator scanIntegrator = new IntentIntegrator(this);
	scanIntegrator.initiateScan();
}
&lt;/pre&gt;&lt;p&gt; As before, we are scanning via Intent, which will prompt the user to download the ZXing barcode scanner if they do not already have it installed. The scanning result will be returned to &lt;em&gt;onActivityResult&lt;/em&gt;, so add it to your class:&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
	//retrieve result of scanning - instantiate ZXing object
	IntentResult scanningResult = IntentIntegrator.parseActivityResult(requestCode, resultCode, intent);
	//check we have a valid result
	if (scanningResult != null) {
		//get content from Intent Result
		String scanContent = scanningResult.getContents();
		//get format name of data scanned
		String scanFormat = scanningResult.getFormatName();
	}
	else{
		//invalid scan data or scan canceled
		Toast toast = Toast.makeText(getApplicationContext(),
				&amp;quot;No book scan data received!&amp;quot;, Toast.LENGTH_SHORT);
		toast.show();
	}
}
&lt;/pre&gt;&lt;p&gt; This is virtually identical to the code we used in the last tutorial except for the reference to the two Text Views which we have removed. We will output information about scanned books in user interface items we create later in the series. For the moment you can add the following line to your &lt;em&gt;onActivityResult&lt;/em&gt; method, inside the &lt;em&gt;if&lt;/em&gt; block, outputting the scan content and format to the log if you wish to run the app in the meantime:&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
Log.v(&amp;quot;SCAN&amp;quot;, &amp;quot;content: &amp;quot;+scanContent+&amp;quot; - format: &amp;quot;+scanFormat);
&lt;/pre&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;2.&lt;/span&gt; Setup Google Books API Access&lt;/h2&gt;&lt;h3&gt;Step 1&lt;/h3&gt;&lt;p&gt; We are going to use Google Books API to retrieve information about books scanned by the user. Sign into your Google account and browse to the &lt;a
href="https://code.google.com/apis/console"&gt;APIs Console&lt;/a&gt;. Select &amp;#8220;Services&amp;#8221; and scroll to the Books API listing. Click to turn Books API on for your account, accepting the terms if prompted.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/books_api.png" alt="Books API" /&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;p&gt; You will need your API key to access the Books API in the app. In your Google APIs Console, select &amp;#8220;API Access&amp;#8221;. If you already have a key it should be listed under &amp;#8220;Key for browser apps&amp;#8221;. If not you can create one by selecting &amp;#8220;Create new Browser key&amp;#8221; and following the instructions. Copy your key for later reference &amp;#8211; we will use it in the next tutorial.&lt;/p&gt;&lt;h3&gt;Step 2&lt;/h3&gt;&lt;p&gt; To use the Google Books API service, we will need Internet access, so finally add the permission to your app Manifest:&lt;/p&gt;&lt;pre class="brush: xml; title: ;"&gt;
&amp;lt;uses-permission android:name=&amp;quot;android.permission.INTERNET&amp;quot; &amp;gt;
&amp;lt;/uses-permission&amp;gt;
&lt;/pre&gt;&lt;hr
/&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt; In this first part of the series we have set the app up to use scanning functionality via ZXing. We have also retrieved an API key for accessing Google Books data. In the next part we will build a book search query and execute it. Over the second and third parts of the series we will fetch and retrieve information about scanned books. Check the source code download to ensure you have everything in the right place before you complete the next part.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MobileTuts/~4/huyZnOySdhU" height="1" width="1"/&gt;</description> <wfw:commentRss>http://mobile.tutsplus.com/tutorials/android/android-sdk-create-a-book-scanning-app/feed/</wfw:commentRss> <slash:comments>0</slash:comments> <feedburner:origLink>http://mobile.tutsplus.com/tutorials/android/android-sdk-create-a-book-scanning-app/</feedburner:origLink></item> <item><title>Build a Monster Smashing Game with Cocos2D: Movement &amp; Animations</title><link>http://feedproxy.google.com/~r/MobileTuts/~3/xNk4ItjJyPo/</link> <comments>http://mobile.tutsplus.com/tutorials/iphone/build-a-monster-smashing-game-with-cocos2d-movement-animations/#comments</comments> <pubDate>Thu, 13 Jun 2013 21:52:01 +0000</pubDate> <dc:creator>Jorge Costa and Orlando Pereira</dc:creator> <category><![CDATA[iOS SDK]]></category> <guid isPermaLink="false">http://mobile.tutsplus.com/?p=17365</guid> <description>&lt;p&gt;This tutorial will teach you how to use the Cocos2D iOS framework in order to create simple yet advanced 2D games aimed at all iOS devices. It&amp;#8217;s designed for both novice and advanced users. Along the way, you&amp;#8217;ll learn about the Cocos2D core concepts, touch interaction, menus and transitions, actions, particles, and collisions. Read on!&lt;br
/&gt;&lt;/p&gt;&lt;p&gt;This tutorial is the second entry in the three-part Monster Smashing series. Make sure you&amp;#8217;ve completed the previous section before beginning.&lt;/p&gt;&lt;hr
/&gt; Organization of the Series:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a
href="http://mobile.tutsplus.com/?p=17352"&gt;Project Structure &amp;#038; Setup&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a
href="http://mobile.tutsplus.com/?p=17365"&gt;Movement &amp;#038; Animations&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a
href="http://mobile.tutsplus.com/?p=17408"&gt;Sound &amp;#038; Game Mechanics&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;In today&amp;#8217;s tutorial we&amp;#8217;ll program the game board for Monster Smashing. This part focuses on several things, including the &lt;code&gt;MonsterRun&lt;/code&gt; class, movements, animations, touches, and so on. We&amp;#8217;ll explain everything in the tutorial below.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;1.&lt;/span&gt; Monsters&lt;/h2&gt;&lt;p&gt;Monsters are the main objects of the game. Each monster has a few unique attributes like sprites, movement, velocity, and kill action. To represent an object we can use a specific class, so we&amp;#8217;ve created a &lt;code&gt;Monster&lt;/code&gt; class to represent a monster.&lt;/p&gt;&lt;p&gt;Usually, in Objective-C, we create a new &lt;code&gt;NSObject&lt;/code&gt; subclass. In this case, we need to use the &lt;code&gt;CCNode&lt;/code&gt; class, which is a class that includes the &lt;code&gt;Foundation.h&lt;/code&gt; and the &lt;code&gt;cocos2d.h&lt;/code&gt; headers. To create a new class in Xcode, choose &lt;strong&gt;File -&gt; New -&gt; New File&amp;#8230;&lt;/strong&gt;. In the left-hand table of the panel that appears, select Cocos2D from the iOS section. Select &lt;strong&gt;CCNode&lt;/strong&gt; class from the upper panel and hit &lt;strong&gt;next&lt;/strong&gt;. We&amp;#8217;ll name the class &amp;#8220;Monster&amp;#8221;.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Cocos2D-Tutorial_Part-Two_1.png" alt="Figure 1: CCNode Class" /&gt;&lt;/p&gt; &lt;figcaption&gt;Illustration of the Template Chooser (Xcode).&lt;/figcaption&gt; &lt;/figure&gt;&lt;p&gt;Now we need to declare the instance variables. In Monster.h, add five instance variables:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;NSString *monsterSprite&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;NSString *splashSprite&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;int movement&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;float minVelocity&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;float maxVelocity&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;int killMethod&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Now, as with every oriented object language, we need to implement the setters and getters. In objective-C, properties are a convenient alternative to writing out accessors for instance variables. It saves a lot of typing and it makes your class files easier to read. Add the above-mentioned properties on the .h file.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
@property(nonatomic,readwrite,retain) NSString *monsterSprite;
@property(nonatomic,readwrite,retain) NSString *splashSprite;
@property(nonatomic, readwrite) int movement;
@property(nonatomic, readwrite) float minVelocity;
@property(nonatomic, readwrite) float maxVelocity;
@property(nonatomic, readwrite) int killMethod;
&lt;/pre&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;2.&lt;/span&gt; Initializing the Gameboard&lt;/h2&gt;&lt;p&gt;Before continuing, you&amp;#8217;ll need to initialize several things. we can add a background to our game just like we did in the first section of the tutorial. We can use the same one in the menu scene. If you don&amp;#8217;t remember how to do that, you can use the following code on the &lt;code&gt;-(id) init&lt;/code&gt; method (MonsterRun.m).&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
self.isTouchEnabled = YES;
// Add background
        winSize = [CCDirector sharedDirector].winSize;
        CCSprite *background = [CCSprite spriteWithFile:@&amp;quot;WoodRetroApple_iPad_HomeScreen.jpg&amp;quot;];
        background.position = ccp(winSize.width/2, winSize.height/2);
        [self addChild:background z:-2];
&lt;/pre&gt;&lt;p&gt;Now we need to initialize some &amp;#8220;monsters&amp;#8221;. Before you start adding monsters, we need to create a &lt;strong&gt;NSMutableArray&lt;/strong&gt; in order to store them. Once again, the images for the monster sprites are available in the resources folder.&lt;/p&gt;&lt;p&gt;We&amp;#8217;d also like to thank &lt;a
href="http://www.behance.net/Bellones"&gt;Rodrigo Bellão&lt;/a&gt; for providing us with the images for the monsters.&lt;/p&gt;&lt;p&gt;In &lt;code&gt;MonsterRun.m&lt;/code&gt; add two NSMutableArray objects: &lt;strong&gt;_monsters&lt;/strong&gt; and &lt;strong&gt;_monstersOnScreen&lt;/strong&gt;. Then, in the &lt;code&gt;init&lt;/code&gt; method, we must initialize those arrays in order to use them. The following snippet can help us achieve that.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
        //initializing monsters
        _monsters = [[NSMutableArray alloc] init];
        _monstersOnScreen = [[NSMutableArray alloc] init];
        Monster *m1 = [[Monster alloc] init];
        [m1 setTag:1];
        [m1 setMonsterSprite:[[NSString alloc] initWithString:@&amp;quot;monsterGreen.png&amp;quot;]];
        [m1 setSplashSprite:[[NSString alloc] initWithString:@&amp;quot;splashMonsterGreen.png&amp;quot;]];
        [m1 setMinVelocity:2.0];
        [m1 setMaxVelocity:8.0];
        [m1 setMovement:1];
        [m1 setKillMethod:1];
        [_monsters addObject:m1];
        Monster *m2 = [[Monster alloc] init];
        [m2 setTag:2];
        [m2 setMonsterSprite:[[NSString alloc] initWithString:@&amp;quot;monsterBlue.png&amp;quot;]];
        [m2 setSplashSprite:[[NSString alloc] initWithString:@&amp;quot;splashMonsterBlue.png&amp;quot;]];
        [m2 setMinVelocity:2.0];
        [m2 setMaxVelocity:8.0];
        [m2 setKillMethod:2];
        [m2 setMovement:1];
        [_monsters addObject:m2];
        Monster *m3 = [[Monster alloc] init];
        [m3 setTag:3];
        [m3 setMonsterSprite:[[NSString alloc] initWithString:@&amp;quot;monsterRed.png&amp;quot;]];
        [m3 setSplashSprite:[[NSString alloc] initWithString:@&amp;quot;splashMonsterRed.png&amp;quot;]];
        [m3 setMinVelocity:3.0];
        [m3 setMaxVelocity:6.0];
        [m3 setKillMethod:1];
        [m3 setMovement:2];
        [_monsters addObject:m3];
&lt;/pre&gt;&lt;p&gt;These arrays should be used to store all the monsters for a given level.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;3.&lt;/span&gt; Adding Monsters to the Screen&lt;/h2&gt;&lt;p&gt;Now that we have some monsters on memory, the next step is to put them on screen. To do that, we just need a few lines.&lt;/p&gt;&lt;p&gt;First we need to create a scheduler to invoke a method to a specific action which, in this case, is the monster location and movement. Right next to the monster&amp;#8217;s allocation, we can create the scheduler as the next line presents.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
[self schedule:@selector(addMonster:) interval:1.0];
&lt;/pre&gt;&lt;p&gt;The selector indicates the method that will be called &lt;code&gt;addMonster&lt;/code&gt;. At the moment, we don&amp;#8217;t have that method, but it will be created soon. The scheduler can also receive a time interval that represents the time when a specific sprite is updated.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;addMonster&lt;/code&gt; method is the one responsible for the monster movement. Since we&amp;#8217;ve added three different monsters, we will also create three different movement patterns. The &lt;code&gt;addMonster&lt;/code&gt; method is depicted below.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
- (void) addMonster:(ccTime)dt {
    //select a random monster from the _monsters Array
    int selectedMonster = arc4random() % [_monsters count];
    //get some monster caracteristics
    Monster *monster = [_monsters objectAtIndex:selectedMonster];
    int m = [monster movement];
    //!IMPORTANT -- Every Sprite in Screen must be an new CCSprite! Each Sprite can only be one time on screen
    CCSprite *spriteMonster = [[CCSprite alloc] initWithFile:[monster monsterSprite]];
    spriteMonster.tag = [monster tag];
    //BLOCK 1 - Determine where to spawn the monster along the Y axis
    CGSize winSize = [CCDirector sharedDirector].winSize;
    int minX = spriteMonster.contentSize.width / 2;
    int maxX = winSize.width - spriteMonster.contentSize.width/2;
    int rangeX = maxX - minX;
    int actualY = (arc4random() % rangeX) + minX;
    //BLOCK 2 - Determine speed of the monster
    int minDuration = [monster minVelocity];
    int maxDuration = [monster maxVelocity];
    int rangeDuration = maxDuration - minDuration;
    int actualDuration = (arc4random() % rangeDuration) + minDuration;
    if(m == 1){ //STRAIGHT MOVIMENT
        //BLOCK 3 - Create the monster slightly off-screen along the right edge,
        // and along a random position along the Y axis as calculated above
        spriteMonster.position = ccp( actualY,winSize.height + spriteMonster.contentSize.height/2);
        [self addChild:spriteMonster];
        //BLOCK 4 - Create the actions
        CCMoveTo * actionMove = [CCMoveTo actionWithDuration:actualDuration position:ccp( actualY,-spriteMonster.contentSize.height/2)];
        CCCallBlockN * actionMoveDone = [CCCallBlockN actionWithBlock:^(CCNode *node) {
            [_monstersOnScreen removeObject:node];
            [node removeFromParentAndCleanup:YES];
        }];
        [spriteMonster runAction:[CCSequence actions:actionMove, actionMoveDone, nil]];
        [_monstersOnScreen addObject:spriteMonster];
    }
    else if(m == 2){ //ZIGZAG-SNAKE MOVIMENT
        /* Create the monster slightly off-screen along the right edge,
         and along a random position along the Y axis as calculated above
         */
        spriteMonster.position = ccp( actualY,winSize.height + spriteMonster.contentSize.height/2);
        [self addChild:spriteMonster];
        CCCallBlockN * actionMoveDone = [CCCallBlockN actionWithBlock:^(CCNode *node) {
            [_monstersOnScreen removeObject:node];
            [node removeFromParentAndCleanup:YES];
        }];
        // ZigZag movement Start
        NSMutableArray *arrayBezier = [[NSMutableArray alloc] init];
        ccBezierConfig bezier;
        id bezierAction1;
        float splitDuration = actualDuration / 6.0;
        for(int i = 0; i&amp;lt; 6; i++){
            if(i % 2 == 0){
                bezier.controlPoint_1 = ccp(actualY+100,winSize.height-(100+(i*200)));
                bezier.controlPoint_2 = ccp(actualY+100,winSize.height-(100+(i*200)));
                bezier.endPosition = ccp(actualY,winSize.height-(200+(i*200)));
                bezierAction1 = [CCBezierTo actionWithDuration:splitDuration bezier:bezier];
            }
            else{
                bezier.controlPoint_1 = ccp(actualY-100,winSize.height-(100+(i*200)));
                bezier.controlPoint_2 = ccp(actualY-100,winSize.height-(100+(i*200)));
                bezier.endPosition = ccp(actualY,winSize.height-(200+(i*200)));
                bezierAction1 = [CCBezierTo actionWithDuration:splitDuration bezier:bezier];
            }
            [arrayBezier addObject:bezierAction1];
        }
        [arrayBezier addObject:actionMoveDone];
        id seq = [CCSequence actionsWithArray:arrayBezier];
        [spriteMonster runAction:seq];
        // ZigZag movement End
        [_monstersOnScreen addObject:spriteMonster];
    }
}
&lt;/pre&gt;&lt;p&gt;You may have noticed that there are comments within the code. The comments will guide us (both programmers and readers) to implement and learn each instruction. In this tutorial, the monsters are chosen randomly (however, in part three we&amp;#8217;ll show how use pList to put the monsters on the screen).&lt;/p&gt;&lt;p&gt;The first line of our code does exactly that. We get the total number of monsters on our array and then we randomly choose which one we will put onscreen next. After the monster is selected, we define some properties such as movement, velocity, range over the XX axis and its tag.&lt;/p&gt;&lt;p&gt;We defined three &lt;strong&gt;Blocks&lt;/strong&gt; that define specific properties.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Block 1 determines where on screen we will span the monsters. Note that the monster will only spawn in a visible area of screen. For that, we get the range of the XX axis and then randomly place the monster.&lt;/li&gt;&lt;li&gt;Block 2 determines the speed of the monster. Note that each monster&amp;#8217;s type will have the minimum and maximum speed defined. The speed of the monster is the duration in seconds that the monster will pass through the screen. This duration will be between the &lt;strong&gt;minDuration&lt;/strong&gt; and the &lt;strong&gt;maxDuration&lt;/strong&gt; defined on the monster object on the &lt;code&gt;init&lt;/code&gt; method&lt;/li&gt;&lt;li&gt;Block 3 creates the monster slightly off-screen along the right edge and along a random position along the XX axis, calculated above&lt;/li&gt;&lt;li&gt;Block 4 creates the actions for the straight movement. Two actions are created, the movement itself &lt;code&gt;CCMoveTo * actionMove&lt;/code&gt; and one that is called when the sprite leaves the screen (&lt;code&gt;CCCallBlockN * actionMoveDone&lt;/code&gt;). To create an action with straight movement, we use the &lt;code&gt;CCMoveTo&lt;/code&gt; object, which receives the duration of the action and the final position. We also use the &lt;code&gt;CCCallBlockN&lt;/code&gt;. This particular object will detect when a monster gets off the screen. Using the &lt;code&gt;CCCallBlockN&lt;/code&gt; is advantageous because Cocos2D already has some mechanisms in place to detect if a particular resource leaves the screen.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;We have defined two movements: straight and zig-zag. The straight one can be analyzed in Block 4, mentioned above. The zig-zag uses the bezier path to create the zig-zag effect and will be depicted below.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;4.&lt;/span&gt; The Zig-Zag (Snake) Movement&lt;/h2&gt;&lt;p&gt;To make the zig-zag movement we use the &lt;code&gt;CCBezier&lt;/code&gt;. This class allow us to create an action that will move the target with a cubic bezier curve to a destination point.&lt;/p&gt;&lt;p&gt;The created curves will always move 100 pixels to the left or right, and at the same time the object will move 200 pixels below. The &lt;code&gt;for&lt;/code&gt; loop will create the path of the monster. Since the screen, which is the normal iPad resolution, has 1024 pixels in the vertical position, we need to run the loop six times (200px * 6 = 1200px). The condition inside the &lt;code&gt;for&lt;/code&gt; loop will determine if the iteration is odd or pair. When the number is odd, the monster move to the left. If the number is pair, the monster moves to the right.&lt;/p&gt;&lt;p&gt;Now each condition will calculate the &lt;code&gt;controlPoint1&lt;/code&gt; and &lt;code&gt;controlPoint2&lt;/code&gt;, which are used to control and guide the curve on screen. The &lt;code&gt;endPosition&lt;/code&gt;, as the name suggests, is the final position that each monster will end up in after each curve. We concatenate all these actions into an array and create a sequence from it. Just as we did with the straight movement, we&amp;#8217;ll run the action and add the monster to the array.&lt;/p&gt;&lt;p&gt;It&amp;#8217;s now time to build and run the project. Your game should look similar to the image below.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Cocos2D-Tutorial_Part-Two_2.png" alt="Figure 2: Monster on Screen" /&gt;&lt;/p&gt; &lt;figcaption&gt;Illustration of the game with several monsters.&lt;/figcaption&gt; &lt;/figure&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;5.&lt;/span&gt; Touch Interaction&lt;/h2&gt;&lt;p&gt;A game with monsters that cannot be killed is not a game, right?&lt;/p&gt;&lt;p&gt;It&amp;#8217;s time to add some interaction between the screen and the user. We&amp;#8217;ll follow the same philosophy we used above, code and explanation.&lt;/p&gt;&lt;p&gt;Cocos2D provides us with several mechanisms for touch interaction. For now, we&amp;#8217;ll only focus on one touch. For that, we need to add a specific method called &lt;code&gt;ccTouchesBegan&lt;/code&gt;. The method receives an event and will act accordingly to that event. Obviously, the event is a touch event. The snippet is presented below.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
-(void)ccTouchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    NSMutableArray *monstersToDelete = [[NSMutableArray alloc] init];
    UITouch * touch = [[touches allObjects] objectAtIndex:0];
    CGPoint touchLocation = [self convertTouchToNodeSpace:touch];
    for (CCSprite *monster in _monstersOnScreen) {
        if (CGRectContainsPoint(monster.boundingBox, touchLocation)) {
            [monstersToDelete addObject:monster];
            //add animation with fade - splash
            Monster *m = [_monsters objectAtIndex:(monster.tag-1)];
            CCSprite *splashPool = [[CCSprite alloc] initWithFile:[m splashSprite]];
            if([m killMethod] == 1){
                splashPool.position = monster.position;
                [self addChild:splashPool];
                CCFadeOut *fade = [CCFadeOut actionWithDuration:3];  //this will make it fade
                CCCallFuncN *remove = [CCCallFuncN actionWithTarget:self selector:@selector(removeSprite:)];
                CCSequence *sequencia = [CCSequence actions: fade, remove, nil];
                [splashPool runAction:sequencia];
                //finish splash
            }
            if([m killMethod] == 2){
                // in Part 3 - Particles section
            }
            break;
        }
    }
     for (CCSprite *monster in monstersToDelete) {
         [monster stopAllActions];
         [_monstersOnScreen removeObject:monster];
         [self removeChild:monster cleanup:YES];
&lt;/pre&gt;&lt;p&gt;The first line of this method is the allocation of an auxiliary array &lt;code&gt;monstersToDelete&lt;/code&gt; that defines what monsters will be deleted at each action.&lt;/p&gt;&lt;p&gt;The next step is to know the touch interaction location. With that location, we&amp;#8217;ll loop all the sprites on the screen and test to see if the touch location is inside an invisible box that contains a monster. We&amp;#8217;ll use &lt;code&gt;f (CGRectContainsPoint(monster.boundingBox, touchLocation))&lt;/code&gt;. If it is true, we&amp;#8217;ll add the monsters to the auxiliary array. Plus, we&amp;#8217;ll add two splash animations when a monster is killed. The first one is a simple splash, while the second is a particle. We&amp;#8217;ll discuss that in part three. To create the splash, we verify the monster type and then we add that monster to a splash pool. &lt;code&gt;CCFadeOut&lt;/code&gt; will create a fade effect on the splash image, and the &lt;code&gt;CCCallFuncN&lt;/code&gt; will call another method to remove the Monster sprite.&lt;/p&gt;&lt;p&gt;Now we just need one little thing. In the &lt;code&gt;CCCallFuncN *remove&lt;/code&gt;, the call method &lt;code&gt;removeSprite&lt;/code&gt; needs to be created and the objective is to remove that sprite. Add that method using the following code.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
-(void) removeSprite:(id)sender {
    [self removeChild:sender cleanup:YES];
}
&lt;/pre&gt;&lt;p&gt;Finally, when the loop is over, the touch interaction is tested against all objects in the scene we have in another loop, &lt;code&gt;for (CCSprite *monster in monstersToDelete)&lt;/code&gt;. It will iterate over &lt;code&gt;monstersToDelete&lt;/code&gt; and remove the object.&lt;/p&gt;&lt;p&gt;It&amp;#8217;s now time to build and run the project. We should see some monsters popping up onscreen. Now we can start killing them! You will notice that the red monsters don&amp;#8217;t have any splash when they die. This will be covered in the next part. The final image in this part is the following.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Cocos2D-Tutorial_Part-Two_3.png" alt="Figure 1: Monster on Screen with splash animation" /&gt;&lt;/p&gt; &lt;figcaption&gt;Illustration of the game with several monsters with splash animation.&lt;/figcaption&gt; &lt;/figure&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;6.&lt;/span&gt; Conclusion&lt;/h2&gt;&lt;p&gt;At this point you should be able to understand and perform the following tasks:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Add sprites to the screen.&lt;/li&gt;&lt;li&gt;Define sprite properties.&lt;/li&gt;&lt;li&gt;Define custom classes.&lt;/li&gt;&lt;li&gt;Initialize the game board.&lt;/li&gt;&lt;li&gt;Define custom movements and actions.&lt;/li&gt;&lt;li&gt;Know how to use touch interaction.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;In the next tutorial we&amp;#8217;ll learn about sound and game mechanics!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MobileTuts/~4/xNk4ItjJyPo" height="1" width="1"/&gt;</description> <wfw:commentRss>http://mobile.tutsplus.com/tutorials/iphone/build-a-monster-smashing-game-with-cocos2d-movement-animations/feed/</wfw:commentRss> <slash:comments>0</slash:comments> <feedburner:origLink>http://mobile.tutsplus.com/tutorials/iphone/build-a-monster-smashing-game-with-cocos2d-movement-animations/</feedburner:origLink></item> <item><title>Check Out the New Recommended Resources on Mobiletuts+</title><link>http://feedproxy.google.com/~r/MobileTuts/~3/lQjc20tQV3k/</link> <comments>http://mobile.tutsplus.com/articles/news/resources/#comments</comments> <pubDate>Tue, 11 Jun 2013 21:10:25 +0000</pubDate> <dc:creator>Sean Hodge</dc:creator> <category><![CDATA[News]]></category> <category><![CDATA[resources]]></category> <guid isPermaLink="false">http://mobile.tutsplus.com/?p=18003</guid> <description>&lt;p&gt;We&amp;#8217;ve added a new page to the site, which will help mobile design and development professionals grab top quality software and tools. It&amp;#8217;s filled with our &lt;a
href="http://mobile.tutsplus.com/resources"&gt;favorite resources that we recommend for mobile app developers&lt;/a&gt;. You can jump straight over to our &lt;a
href="http://mobile.tutsplus.com/resources"&gt;Recommended Resources&lt;/a&gt; page here on Mobiletuts+ or read on for further information.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Hand Picked Resources for Mobile App Professionals&lt;/h2&gt;&lt;p&gt;Our Tuts+ editorial team has hand-picked these resources, which feature core applications, hosting recommendations, editors, testing, and deployment services. Our goal here is to feature the highest quality, useful resources that we highly recommend and in most cases use ourselves. It&amp;#8217;s a quick stop to finding the best of the best when you have an urgent need to fill as a mobile creative professional.&lt;/p&gt;&lt;p&gt;Keep an eye out for more of these site sections as our Resource pages roll out across the Tuts+ network.&lt;/p&gt;&lt;div
class="tutorial_image"&gt;&lt;a
href="http://mobile.tutsplus.com/resources"&gt;&lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/06/mobiletuts-recommended-resources.png" alt="Recommended Resources" width="600" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;h4&gt;Jump over to the &lt;a
href="http://mobile.tutsplus.com/resources"&gt;Mobiletuts+ Recommended Resources&lt;/a&gt; Page&lt;/h4&gt;&lt;/div&gt;&lt;hr
/&gt;&lt;h2&gt;What Mobile App Development Tools Do You Recommend?&lt;/h2&gt;&lt;p&gt;This is version 1.0 of this &lt;a
href="http://mobile.tutsplus.com/resources"&gt;Mobiletuts+ Resources&lt;/a&gt; page. We&amp;#8217;ll continue to add to it and grow this section of the site. We could use your help with that!&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Are there any awesome apps, tools or services that you feel we missed?&lt;/strong&gt; Bounce into the discussion below and leave a comment about what resource you recommend to fellow mobile development experts.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MobileTuts/~4/lQjc20tQV3k" height="1" width="1"/&gt;</description> <wfw:commentRss>http://mobile.tutsplus.com/articles/news/resources/feed/</wfw:commentRss> <slash:comments>0</slash:comments> <feedburner:origLink>http://mobile.tutsplus.com/articles/news/resources/</feedburner:origLink></item> <item><title>Designing a Meaningful Social Layer for Mobile Applications</title><link>http://feedproxy.google.com/~r/MobileTuts/~3/QnWCJn3hHW8/</link> <comments>http://mobile.tutsplus.com/tutorials/mobile-design-tutorials/designing-a-meaningful-social-layer-for-mobile-applications/#comments</comments> <pubDate>Mon, 10 Jun 2013 19:48:29 +0000</pubDate> <dc:creator>Sven Lenaerts</dc:creator> <category><![CDATA[Mobile Design]]></category> <guid isPermaLink="false">http://mobile.tutsplus.com/?p=17884</guid> <description>&lt;p&gt;Applications with social features have become the norm, but, as a designer, it&amp;#8217;s important that you question how these social features add value for the user. In this article, we&amp;#8217;ll explore how to improve an application by designing a meaningful social layer.&lt;/p&gt;&lt;p&gt;&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/06/Meaningful-Social-Layer_1.jpg" alt="social layer" /&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;p&gt;When we talk about social layers, there&amp;#8217;s a lot involved. Basically, we&amp;#8217;re building an interactive experience where people can create, share, and exchange information within a virtual network. The importance of user-generated content has grown enormously. Even a simple output of a social layer can create value for people, like Facebook&amp;#8217;s simple &amp;#8220;&lt;strong&gt;Like&lt;/strong&gt;&amp;#8221; feature. On the flip side, social layers can have negative effects on our lives. They often create an unwanted (and unconscious) pressure to be successful not just in our work and our lives, but within the social media apps we&amp;#8217;re active using.&lt;/p&gt;&lt;p&gt;That being said, it&amp;#8217;s important to make sure that the social aspect we design and build is meaningful and fun. Even better, try to ignore the social layer if it isn&amp;#8217;t relevant to your application. The assumption that the social aspect is mandatory is wrong. When present, social interaction needs to be thoughtfully utilized.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;A Subtle Difference&lt;/h2&gt;&lt;p&gt;The social layer is more extensive than social media. Social media is intended to connect people with people, but a social layer is much more extensive. Social media became a social layer because it connected us with brands, experiences, products, feelings, applications, and games. When we try to connect to something or someone, it&amp;#8217;s a much larger part of our lives than it was just a few years ago. Social media has evolved into a social layer of life and our digital data online, and we spread it through our actions. It has become increasingly valuable for developers to use this layer in their applications.&lt;/p&gt;&lt;p&gt;Understanding the power of a social layer creates a range of possibilities for empowering your application. Social aspects are a cheap way to promote your application and they can improve the features of your application if they&amp;#8217;re relevant to what your application will do.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Qualities of a Good Social Layer&lt;/h2&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/06/Meaningful-Social-Layer_2.jpg" alt="social layer" /&gt;&lt;br
/&gt; &lt;fig
caption&gt;&lt;a
href="http://dribbble.com/shots/419757-Dribbble-Connections" target="_blank"&gt;Dribbble Connections&lt;/a&gt; by Bruce Spang on Dribbble&lt;/fig caption&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;p&gt;Generally, when we&amp;#8217;re talking about social layers we&amp;#8217;re talking about two important characteristics. They either &lt;em&gt;help the user&lt;/em&gt; or &lt;em&gt;help the community&lt;/em&gt;.&lt;/p&gt;&lt;p&gt;When we speak of helping the user, there are a lot of obvious solutions. We can offer them ways to express themselves by creating and sharing content. These features are just an example, but there are numerous options. Still, it&amp;#8217;s important to understand that you shouldn&amp;#8217;t force a social layer in your application if it doesn&amp;#8217;t create any value. Users might not want to share content or compare themselves to other users. Try to understand what the social aspect means for your target audience.&lt;/p&gt;&lt;p&gt;Another important part of the social layer is the sense of community it creates. These can be obvious things, like helping each other through content or building ways to interact with each other.&lt;/p&gt;&lt;p&gt;The interaction you create should be simple, fun, and worth the user&amp;#8217;s time. Try to analyze your own behavior on social media and see how it influences you. Use that as an example for the features you are planning in your application. Generally, people give value to their actions on social media. This is why it&amp;#8217;s important to add social features to your applications in a rewarding way.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Designing The Social Experience&lt;/h2&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/06/Meaningful-Social-Layer_3.jpg" alt="social layer" /&gt;&lt;br
/&gt; &lt;a
href="http://dribbble.com/shots/753765-Diversity" target="_blank"&gt;Diversity&lt;/a&gt; by Andy Mangold on Dribbble&lt;br
/&gt; &lt;/figure&gt;&lt;p&gt;Start by defining your community and understanding what the added value of that community is.&lt;/p&gt;&lt;p&gt;When you&amp;#8217;re dealing with applications, everything starts with the features. Do you believe that a social layer enhances the experience of using your application? What are the advantages and disadvantages?&lt;/p&gt;&lt;p&gt;It&amp;#8217;s also necessary to understand how individuals participate in the community. What action or features are connected with the community? How much effort does such an action cost and what are the rewards? Specify what your social layer looks like. What are the important actions and how do they link to each other? Make a scheme for yourself.&lt;/p&gt;&lt;p&gt;Once you&amp;#8217;ve figured out how you&amp;#8217;d like to add a social layer to your application, think about the technical aspects. How will you handle user data? How will you create your features? How will you integrate every aspect of your social layer into a coherent application? It&amp;#8217;s often very difficult to make everything a streamlined experience, but it&amp;#8217;s important to keep that streamlined user experience in mind even if it costs features in the end.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Best Practices&lt;/h2&gt;&lt;p&gt;This article has been purely theoretical thus far, so let&amp;#8217;s take a look at some applications and see how they made their social aspects a success.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/06/Meaningful-Social-Layer_4.jpg" alt="social layer" /&gt;&lt;br
/&gt; &lt;fig
caption&gt;Foursquare&lt;/fig caption&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;p&gt;One of my favorite examples is Foursquare. They&amp;#8217;ve made the community the most important contributor in their application while also integrating the user&amp;#8217;s personal relationships. They also made all the user interactions within the social layer simple, fun, and accessible.&lt;/p&gt;&lt;p&gt;In addition, FourSquare also did a great job at rewarding the user&amp;#8217;s actions and keeping the application competitive between friends by resetting check-in points weekly. Most of all, it offers useful content and just about everyone can contribute to the experience. They understand how a social layer should work and the social aspect of their application has made it a huge success.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/06/Meaningful-Social-Layer_5.jpg" alt="social layer" /&gt;&lt;br
/&gt; &lt;fig
caption&gt;Flipboard&lt;/fig caption&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;p&gt;Flipboard isn&amp;#8217;t as popular as Foursquare, but they know how to make interaction with content fun. By creating simple navigation gestures and combining them with the ability to integrate social media accounts, Flipboard has made social media interaction much more fun. It&amp;#8217;s still possible to like, comment, or share and it&amp;#8217;s much less cluttered than most social media sites like Facebook.&lt;/p&gt;&lt;p&gt;The social layer they&amp;#8217;ve created is hidden, and it&amp;#8217;s so well done that it doesn&amp;#8217;t even feel like a real social layer. Flipboard is like reading a newspaper that you can interact with. A hidden social layer can work just as well as an obvious one.&lt;/p&gt;&lt;p&gt;What are some of your personal favorite applications which handle the social aspects of applications very well?&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Some Final Tips and Tricks&lt;/h2&gt;&lt;ul&gt;&lt;li&gt;Start on paper. Brainstorm, use feedback, and weigh out your pros and cons.&lt;/li&gt;&lt;li&gt;Don&amp;#8217;t assume that every user wants to interact. Never force it.&lt;/li&gt;&lt;li&gt;If you plan to work with accounts, make registering and logging in very simple and quick.&lt;/li&gt;&lt;li&gt;Add a low-level form of interacting (a like button or checking in)&lt;/li&gt;&lt;li&gt;Add a high-level form of interacting (commenting or leaving tips)&lt;/li&gt;&lt;li&gt;Use a social layer to indirectly promote your application. Sharing is a great example of this.&lt;/li&gt;&lt;li&gt;As a developer, make use of the social layer yourself to interact with your community.&lt;/li&gt;&lt;li&gt;Do some usability tests. It&amp;#8217;s a great idea to use a beta version to find out how streamlined the interaction is.&lt;/li&gt;&lt;li&gt;Finally, if a social layer doesn&amp;#8217;t create any added value for your application, just leave it out.&lt;/li&gt;&lt;/ul&gt;&lt;hr
/&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;Social layers have grown and gained importance. As always, carefully weigh the pros and cons when deciding to use one within your application. Make interaction fun and rewarding, and users will gladly participate in the community you build. Good luck!&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MobileTuts/~4/QnWCJn3hHW8" height="1" width="1"/&gt;</description> <wfw:commentRss>http://mobile.tutsplus.com/tutorials/mobile-design-tutorials/designing-a-meaningful-social-layer-for-mobile-applications/feed/</wfw:commentRss> <slash:comments>0</slash:comments> <feedburner:origLink>http://mobile.tutsplus.com/tutorials/mobile-design-tutorials/designing-a-meaningful-social-layer-for-mobile-applications/</feedburner:origLink></item> <item><title>Android SDK: Create an Interactive Screen Saver with Daydream</title><link>http://feedproxy.google.com/~r/MobileTuts/~3/OoVpccneVjo/</link> <comments>http://mobile.tutsplus.com/tutorials/android/android-sdk-create-an-interactive-screen-saver-with-daydream/#comments</comments> <pubDate>Fri, 07 Jun 2013 16:26:01 +0000</pubDate> <dc:creator>Sue Smith</dc:creator> <category><![CDATA[Android SDK]]></category> <category><![CDATA[android]]></category> <guid isPermaLink="false">http://mobile.tutsplus.com/?p=16604</guid> <description>&lt;p&gt;Daydream interactive screen savers are a new feature in Android 4.2 (API Level 17). With Daydream, you can create a screen saver with animation, interaction, and just about anything else you would include in an Android &lt;strong&gt;Activity&lt;/strong&gt;. Daydream screen savers are displayed while the user device is charging. Users with devices running Jelly Bean 4.2 can select and configure a Daydream screen saver in their display settings. In this tutorial we&amp;#8217;ll go through the required steps to create a Daydream screen saver for Android.&lt;br
/&gt;&lt;/p&gt;&lt;p&gt; The sample Daydream we&amp;#8217;ll create in this tutorial will display a simple animation featuring the Android robot image used as default launcher icon. The user will be able to stop and start the animation by tapping the robots. The Daydream will display a grid with multiple instances of the rotating robot and a button the user can use to dismiss the Daydream, which will be placed randomly within the grid.&lt;/p&gt;&lt;p&gt; In your own projects, you can choose interactive screen saver elements that will reuse the views you have in existing apps, or web views that provide links to your projects. The code in this tutorial is simply intended to familiarize you with the process of creating a functioning interactive Daydream, but these potential applications can enhance user engagement with any existing projects you may have.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; Daydream is only available on devices running version 4.2 of Android, which is API Level 17. If you don&amp;#8217;t have a device running API 17, you&amp;#8217;ll only be able to test your Daydream apps on the emulator. As long as your Android development environment has version 17 installed, you should be able to create an AVD (Android Virtual Device) on which the Daydream will run. During development, you can create a test &lt;strong&gt;Activity&lt;/strong&gt; in which you place the same content as your Daydream apps. The Eclipse and Android development resources are particularly useful for &lt;strong&gt;Activities.&lt;/strong&gt;&lt;/p&gt;&lt;hr/&gt;&lt;h2&gt;&lt;span&gt;1.&lt;/span&gt; Create a Project&lt;/h2&gt;&lt;h3&gt;Step 1&lt;/h3&gt;&lt;p&gt; Create a new Android Project in Eclipse. The app will have one class in it, which will be a &lt;strong&gt;Service&lt;/strong&gt;. When you go through the process of creating your new Android project in Eclipse, select API Level 17 as both target and minimum SDK for your project. There&amp;#8217;s no need to let Eclipse create an &lt;strong&gt;Activity&lt;/strong&gt; or layout file. You won&amp;#8217;t need one. You can, however, let it create a launcher icon. In the New Android Application &amp;#8220;&lt;strong&gt;Configure Project&lt;/strong&gt;&amp;#8221; screen, uncheck &amp;#8220;&lt;strong&gt;Create Activity&lt;/strong&gt;&amp;#8221; but leave &amp;#8220;&lt;strong&gt;Create Custom Launcher Icon&lt;/strong&gt;&amp;#8221; checked. Choose the default Android robot icon; we are going to use it within the Daydream.&lt;/p&gt;&lt;h3&gt;Step 2&lt;/h3&gt;&lt;p&gt; Open your project &lt;strong&gt;Manifest&lt;/strong&gt; file to configure the app as a Daydream. Include the following code within the &lt;strong&gt;Manifest&lt;/strong&gt; application element.&lt;/p&gt;&lt;pre class="brush: xml; title: ;"&gt;
&amp;lt;service
	android:name=&amp;quot;.RobotDaydream&amp;quot;
	android:exported=&amp;quot;true&amp;quot;
	android:label=&amp;quot;@string/daydream_name&amp;quot;&amp;gt;
	&amp;lt;intent-filter&amp;gt;
		&amp;lt;action android:name=&amp;quot;android.service.dreams.DreamService&amp;quot; /&amp;gt;
		&amp;lt;category android:name=&amp;quot;android.intent.category.DEFAULT&amp;quot; /&amp;gt;
	&amp;lt;/intent-filter&amp;gt;
&amp;lt;/service&amp;gt;
&lt;/pre&gt;&lt;p&gt; This allows your app to be listed in the Daydream options within the user&amp;#8217;s display settings. You can change the name of the service class &amp;#8220;&lt;strong&gt;RobotDaydream&lt;/strong&gt;&amp;#8221; if you like, as long as you give your service class the same name when we create it. Add the specified label string to your application&amp;#8217;s &amp;#8220;&lt;strong&gt;res/values/strings&lt;/strong&gt;&amp;#8221; file(s).&lt;/p&gt;&lt;pre class="brush: xml; title: ;"&gt;
&amp;lt;string name=&amp;quot;daydream_name&amp;quot;&amp;gt;Spinning Androids&amp;lt;/string&amp;gt;
&lt;/pre&gt;&lt;p&gt; This name will appear in the device display settings when selecting a Daydream.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/04/daydream_settings.png" alt="Daydream Settings" /&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; The Manifest code above is complete for a functioning Daydream. However, you can opt to &lt;a
href="http://android-developers.blogspot.co.uk/2012/12/daydream-interactive-screen-savers.html"&gt;add a metadata element&lt;/a&gt;, linking to a resource where you can specify a settings &lt;strong&gt;Activity&lt;/strong&gt; class for your app.&lt;/p&gt;&lt;hr/&gt;&lt;h2&gt;&lt;span&gt;2.&lt;/span&gt; Define an Animation&lt;/h2&gt;&lt;h3&gt;Step 1&lt;/h3&gt;&lt;p&gt; Before we get started on the Daydream &lt;strong&gt;Service&lt;/strong&gt; class, we&amp;#8217;ll define an animation set resource. The little robot icons we display will rotate back and forth when the Daydream runs, so let&amp;#8217;s define this animation first. In your project &amp;#8220;&lt;strong&gt;res&lt;/strong&gt;&amp;#8221; folder, create a new folder named &amp;#8220;&lt;strong&gt;animator&lt;/strong&gt;&amp;#8221; and create a new file in it named &amp;#8220;&lt;strong&gt;android_spin.xml&lt;/strong&gt;&amp;#8220;. Inside the new XML file, define the animation.&lt;/p&gt;&lt;pre class="brush: xml; title: ;"&gt;
&amp;lt;set xmlns:android=&amp;quot;http://schemas.android.com/apk/res/android&amp;quot;
	android:interpolator=&amp;quot;@android:anim/linear_interpolator&amp;quot;
	android:ordering=&amp;quot;together&amp;quot; &amp;gt;
	&amp;lt;objectAnimator
	android:duration=&amp;quot;5000&amp;quot;
	android:propertyName=&amp;quot;rotation&amp;quot;
	android:repeatCount=&amp;quot;infinite&amp;quot;
	android:repeatMode=&amp;quot;reverse&amp;quot;
	android:valueTo=&amp;quot;360&amp;quot;
	android:valueType=&amp;quot;floatType&amp;quot; /&amp;gt;
&amp;lt;/set&amp;gt;
&lt;/pre&gt;&lt;p&gt; You can alter the animation properties if you wish. This simply defines an animation that will rotate the target image 360 degrees in one direction over five seconds and back in the opposite direction. It will repeat continuously.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/04/daydream_started.png" alt="Daydream Started" /&gt;&lt;/p&gt; &lt;figcaption&gt;The image views in the grid will rotate back and forth continuously while the Daydream is visible.&lt;/figcaption&gt; &lt;/figure&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;3.&lt;/span&gt; Create a Daydream Service&lt;/h2&gt;&lt;h3&gt;Step 1&lt;/h3&gt;&lt;p&gt; In your project, create a new class in the main package. If Eclipse did not create a default package when you created the project, add one now by selecting the &amp;#8220;&lt;strong&gt;src&lt;/strong&gt;&amp;#8221; folder and choosing &lt;strong&gt;File &gt; New &gt; Package&lt;/strong&gt; and entering your package name. Add your new class to the package, naming it &amp;#8220;&lt;strong&gt;RobotDaydream&lt;/strong&gt;&amp;#8221; or whatever you included in the &lt;strong&gt;Manifest&lt;/strong&gt; service name attribute. Extend the opening line of the class declaration.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
public class RobotDaydream extends DreamService implements OnClickListener
&lt;/pre&gt;&lt;p&gt; You will need the following imports in the class for the remainder of the code in this tutorial.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
import java.util.Random;
import android.animation.AnimatorInflater;
import android.animation.AnimatorSet;
import android.graphics.Color;
import android.graphics.Point;
import android.service.dreams.DreamService;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.GridLayout;
import android.widget.ImageView;
&lt;/pre&gt;&lt;h3&gt;Step 2&lt;/h3&gt;&lt;p&gt; When you extend the Daydream class, there are a number of methods you can override to control the appearance and behavior of your screen saver. Inside your &lt;strong&gt;Service&lt;/strong&gt; class, add the method outline for when the Daydream starts.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
@Override
public void onDreamingStarted() {
//daydream started
}
&lt;/pre&gt;&lt;p&gt; Now add the method outline for when Daydreaming stops.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
@Override
public void onDreamingStopped(){
//daydream stopped
}
&lt;/pre&gt;&lt;p&gt; Add the method outline for when your Daydream is initially attached. You&amp;#8217;ll include setup tasks for the screen saver.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
@Override
public void onAttachedToWindow() {
//setup daydream
}
&lt;/pre&gt;&lt;p&gt; Any tidying up from setup will be placed inside the method for when the Daydream is detached, so add that next.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
@Override
public void onDetachedFromWindow() {
//tidy up
}
&lt;/pre&gt;&lt;p&gt; Lastly, add the method outline for handling clicks. Depending on their functionality, your Daydream apps may not always require all of these methods.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
public void onClick(View v){
//handle clicks
}
&lt;/pre&gt;&lt;p&gt; We will be working with each of these methods.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;4.&lt;/span&gt; Prepare for Daydreaming&lt;/h2&gt;&lt;h3&gt;Step 1&lt;/h3&gt;&lt;p&gt; At the top of your Daydream &lt;strong&gt;Service&lt;/strong&gt; class, add some instance variables that we&amp;#8217;ll use to implement the animation and interaction. First you&amp;#8217;ll add a button so that the user can stop the Daydream.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
private Button dismissBtn;
&lt;/pre&gt;&lt;p&gt; If you set your Daydream up to be interactive, which we&amp;#8217;ll do here, you&amp;#8217;ll need to manually implement a way to stop the Daydream. Otherwise, the default behavior for a Daydream is to stop when the user touches the screen. We won&amp;#8217;t be using the default behavior because we want to allow the user to interact with the views in our Daydream. We&amp;#8217;ll provide a button that allows the user to dismiss the Daydream instead.&lt;/p&gt;&lt;p&gt; Next, add two arrays.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
private ImageView[] robotImgs;
private AnimatorSet[] robotSets;
&lt;/pre&gt;&lt;p&gt; These will store the robot image views and animator sets for them. We&amp;#8217;ll use a constant to set the number of robots to display, using the number of rows and columns we want in the grid.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
private final int ROWS_COLS=5;
private final int NUM_ROBOTS=ROWS_COLS*ROWS_COLS;
&lt;/pre&gt;&lt;p&gt; Finally, we&amp;#8217;ll use a random number to determine where the stop button will be placed in the grid.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
private int randPosn;
&lt;/pre&gt;&lt;h3&gt;Step 2&lt;/h3&gt;&lt;p&gt; The &lt;strong&gt;onAttachedToWindow&lt;/strong&gt; method gives us the opportunity to carry out setup tasks for the Daydream. Call the superclass method inside the method.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
super.onAttachedToWindow();
&lt;/pre&gt;&lt;p&gt; Set the Daydream to be interactive and occupy the full screen, hiding the status bar.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
setInteractive(true);
setFullscreen(true);
&lt;/pre&gt;&lt;h3&gt;Step 3&lt;/h3&gt;&lt;p&gt; Get a random number to determine where the stop button will be.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
Random rand = new Random();
randPosn = rand.nextInt(NUM_ROBOTS);
&lt;/pre&gt;&lt;p&gt; Create a grid layout for the Daydream, setting the number of rows and columns using the constant.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
GridLayout ddLayout = new GridLayout(this);
ddLayout.setColumnCount(ROWS_COLS);
ddLayout.setRowCount(ROWS_COLS);
&lt;/pre&gt;&lt;p&gt; Initialize the arrays.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
robotSets = new AnimatorSet[NUM_ROBOTS];
robotImgs = new ImageView[NUM_ROBOTS];
&lt;/pre&gt;&lt;p&gt; Determine the width and height for each robot image in the grid.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
Point screenSize = new Point();
getWindowManager().getDefaultDisplay().getSize(screenSize);
int robotWidth = screenSize.x/ROWS_COLS;
int robotHeight = screenSize.y/ROWS_COLS;
&lt;/pre&gt;&lt;h3&gt;Step 4&lt;/h3&gt;&lt;p&gt; Now we can loop through the arrays, adding the stop button and robots to the grid.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
for(int r=0; r&amp;lt;NUM_ROBOTS; r++){
//add to grid
}
&lt;/pre&gt;&lt;p&gt; Inside the loop, create some layout parameters using the width and height we calculated.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
GridLayout.LayoutParams ddP = new GridLayout.LayoutParams();
ddP.width=robotWidth;
ddP.height=robotHeight;
&lt;/pre&gt;&lt;p&gt; Check to make sure we are at the index allocated for the stop button.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
if(r==randPosn){
//stop button
}
else{
//robot image view
}
&lt;/pre&gt;&lt;p&gt; Inside the &lt;strong&gt;if&lt;/strong&gt; block, create and add the stop button to the layout, setting display properties and listening for clicks.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
dismissBtn = new Button(this);
dismissBtn.setText(&amp;quot;stop&amp;quot;);
dismissBtn.setBackgroundColor(Color.WHITE);
dismissBtn.setTextColor(Color.RED);
dismissBtn.setOnClickListener(this);
dismissBtn.setLayoutParams(ddP);
ddLayout.addView(dismissBtn);
&lt;/pre&gt;&lt;p&gt; Inside the &lt;strong&gt;else&lt;/strong&gt; block, create an &lt;strong&gt;Image View&lt;/strong&gt; and set the launcher icon as its drawable, adding it to the layout.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
robotImgs[r] = new ImageView(this);
robotImgs[r].setImageResource(R.drawable.ic_launcher);
ddLayout.addView(robotImgs[r], ddP);
&lt;/pre&gt;&lt;p&gt; Inside the &lt;strong&gt;else&lt;/strong&gt;, create and add an animator set to the array, referencing the animation resource we created. You can alter the drawable image to suit one of your own.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
robotSets[r] = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.android_spin);
&lt;/pre&gt;&lt;p&gt; Set the current robot image as target for the animation and listen for clicks on it.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
robotSets[r].setTarget(robotImgs[r]);
robotImgs[r].setOnClickListener(this);
&lt;/pre&gt;&lt;p&gt; After the &lt;strong&gt;for&lt;/strong&gt; loop (but still inside the &lt;strong&gt;onAttachedToWindow&lt;/strong&gt; method), set the content view to the layout we created and populated.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
setContentView(ddLayout);
&lt;/pre&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;5.&lt;/span&gt; Handle Clicks&lt;/h2&gt;&lt;h3&gt;Step 1&lt;/h3&gt;&lt;p&gt; Inside your &lt;strong&gt;onClick&lt;/strong&gt; method, find out whether a robot image view or the stop button was clicked.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
if(v instanceof Button &amp;amp;&amp;amp; (Button)v==dismissBtn){
//stop button
}
else {
//robot image
}
&lt;/pre&gt;&lt;h3&gt;Step 2&lt;/h3&gt;&lt;p&gt; In the &lt;strong&gt;if&lt;/strong&gt; block, finish the Daydream.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
this.finish();
&lt;/pre&gt;&lt;p&gt; You must implement this for any interactive Daydreams you create (in which you call &lt;strong&gt;setInteractive(true)&lt;/strong&gt;). The user will not be able to dismiss the screen saver the default way.&lt;/p&gt;&lt;h3&gt;Step 3&lt;/h3&gt;&lt;p&gt; Inside the &lt;strong&gt;else&lt;/strong&gt; block, add a loop to iterate through the robot image views.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
for(int r=0; r&amp;lt;NUM_ROBOTS; r++){
//check array
}
&lt;/pre&gt;&lt;p&gt; Inside the loop, make sure that the index is not in the position designated for the stop button. If this is the case, the image view array entry will be empty.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
if(r!=randPosn){
//check image view
}
&lt;/pre&gt;&lt;p&gt; Inside the &lt;strong&gt;if&lt;/strong&gt; block, find out if the current view is the one just clicked.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
if((ImageView)v==robotImgs[r]){
//is the current view
}
&lt;/pre&gt;&lt;p&gt; Inside this &lt;strong&gt;if&lt;/strong&gt;, stop or start the animation depending on whether it&amp;#8217;s currently running.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
if(robotSets[r].isStarted()) robotSets[r].cancel();
else robotSets[r].start();
&lt;/pre&gt;&lt;p&gt; This lets the user turn the animations on and off for each robot image view. Now that we&amp;#8217;ve responded to the click, break out of the loop.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
break;
&lt;/pre&gt;&lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/04/daydream_interaction.png" alt="Daydream Interaction" /&gt;&lt;/p&gt; &lt;figcaption&gt;Clicking the image views will start and stop the animations, clicking the stop button will dismiss the Daydream.&lt;/figcaption&gt; &lt;/figure&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;6.&lt;/span&gt; Starting and Stopping Daydreaming&lt;/h2&gt;&lt;h3&gt;Step 1&lt;/h3&gt;&lt;p&gt; In your &lt;strong&gt;onDreamingStarted&lt;/strong&gt; method, call the superclass method.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
super.onDreamingStarted();
&lt;/pre&gt;&lt;p&gt; Next, loop through the animations and start them.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
for(int r=0; r&amp;lt;NUM_ROBOTS; r++){
	if(r!=randPosn)
		robotSets[r].start();
}
&lt;/pre&gt;&lt;h3&gt;Step 2&lt;/h3&gt;&lt;p&gt; In your &lt;strong&gt;onDreamingStopped&lt;/strong&gt; method, stop the animations.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
for(int r=0; r&amp;lt;NUM_ROBOTS; r++){
	if(r!=randPosn)
		robotSets[r].cancel();
}
&lt;/pre&gt;&lt;p&gt; Now call the superclass method.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
super.onDreamingStopped();
&lt;/pre&gt;&lt;h3&gt;Step 3&lt;/h3&gt;&lt;p&gt; In the &lt;strong&gt;onDetachedFromWindow&lt;/strong&gt; method, we can get rid of anything we set up in &lt;strong&gt;onAttachedToWindow&lt;/strong&gt;. In this case we&amp;#8217;ll just stop listening for clicks.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
for(int r=0; r&amp;lt;NUM_ROBOTS; r++){
	if(r!=randPosn)
		robotImgs[r].setOnClickListener(null);
}
&lt;/pre&gt;&lt;p&gt; Finally, call the superclass method.&lt;/p&gt;&lt;pre class="brush: java; title: ;"&gt;
super.onDetachedFromWindow();
&lt;/pre&gt;&lt;hr
/&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt; This completes the basic Daydream app! You can test yours on the emulator or on a real device running Jelly Bean 4.2. Browsing to the &lt;strong&gt;Settings &gt; Display&lt;/strong&gt; section of the device menu will let you select the Daydream from the available list. Once it&amp;#8217;s selected, you can choose &amp;#8220;&lt;strong&gt;Start Now&lt;/strong&gt;&amp;#8221; to see it in action. In your own projects, you can implement pretty much the same interactive and informational functions you would in an &lt;strong&gt;Activity&lt;/strong&gt;, so you can use Daydreams to provide engaging access points for your existing apps. However, be aware that if your screen saver is using too much of the available processing resources, the Android system will stop it from running to allow the device to charge properly. Other options to explore in your Daydream apps include setting the screen brightness and providing a settings activity for user configuration.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MobileTuts/~4/OoVpccneVjo" height="1" width="1"/&gt;</description> <wfw:commentRss>http://mobile.tutsplus.com/tutorials/android/android-sdk-create-an-interactive-screen-saver-with-daydream/feed/</wfw:commentRss> <slash:comments>1</slash:comments> <feedburner:origLink>http://mobile.tutsplus.com/tutorials/android/android-sdk-create-an-interactive-screen-saver-with-daydream/</feedburner:origLink></item> <item><title>Create a Weather App with Forecast – User Interface</title><link>http://feedproxy.google.com/~r/MobileTuts/~3/GLazVui9oEo/</link> <comments>http://mobile.tutsplus.com/tutorials/iphone/create-a-weather-app-with-forecast-user-interface/#comments</comments> <pubDate>Mon, 03 Jun 2013 20:12:56 +0000</pubDate> <dc:creator>Bart Jacobs</dc:creator> <category><![CDATA[iOS SDK]]></category> <guid isPermaLink="false">http://mobile.tutsplus.com/?p=17772</guid> <description>&lt;p&gt;In the last article of this series, I will show you how to create the user interface of our weather application. Thanks to the work of &lt;a
href="http://vector.tutsplus.com/author/chris-carey/"&gt;Chris Carey&lt;/a&gt;, a regular contributor of &lt;a
href="http://vector.tutsplus.com/"&gt;Vector Tuts+&lt;/a&gt;, we have a beautiful design that we can work with!&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;Introduction&lt;/h2&gt;&lt;p&gt;For the design of our weather application, I collaborated with &lt;a
href="http://vector.tutsplus.com/author/chris-carey/"&gt;Chris Carey&lt;/a&gt;, a regular contributor of &lt;a
href="http://vector.tutsplus.com/"&gt;Vectortuts+&lt;/a&gt;. Chris crafted a beautiful design that we can use to create the application&amp;#8217;s user interface. After Chris handed me the design as a vector illustration, I sliced the artwork and prepared it for use in our project. You can find the sliced artwork in the source files of this article.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130530-1.png" alt="Create a Weather App with Forecast – User Interface - Chris Carey's Design " /&gt;&lt;br
/&gt; &lt;/figure&gt; &lt;figcaption&gt;Figure 1: Chris Carey&amp;#8217;s Design&lt;/figcaption&gt;&lt;p&gt;Due to the limited customizability of UIKit, we will have to make a few compromises when implementing Chris&amp;#8217; design. The final result, however, will very much look like the design that Chris created for us. Customizing UIKit&amp;#8217;s &lt;code&gt;UISwitch&lt;/code&gt; class, for example, is very limited and we will therefore use a different approach to implement the temperature setting. Chris used two custom fonts for his design, Maven Pro and Mission Gothic. Even though iOS supports custom fonts, we will only use fonts available on iOS.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;1.&lt;/span&gt; Notifications&lt;/h2&gt;&lt;h3&gt;Step 1: Creating String Constants&lt;/h3&gt;&lt;p&gt;Whenever the weather view controller receives weather data from the Forecast API, its own view and the right view need to be updated. This means that we need to notify the forecast view controller and send it the weather data. There are several ways to notify the forecast view controller of such an event. Posting a notification using &lt;code&gt;NSNotificationCenter&lt;/code&gt; is the simplest solution and provides us with the most flexibility. We can use the same solution for updating the user interface after the user has toggled the temperature setting. By sending a notification, every object that is interested in this event can register itself as an observer. I have updated &lt;strong&gt;MTConstants.h/.m&lt;/strong&gt; to create a string constant for each notification.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
extern NSString * const MTRainWeatherDataDidChangeChangeNotification;
extern NSString * const MTRainTemperatureUnitDidChangeNotification;
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
NSString * const MTRainWeatherDataDidChangeChangeNotification = @&amp;quot;com.mobileTuts.MTRainWeatherDataDidChangeChangeNotification&amp;quot;;
NSString * const MTRainTemperatureUnitDidChangeNotification = @&amp;quot;com.mobileTuts.MTRainTemperatureUnitDidChangeNotification&amp;quot;;
&lt;/pre&gt;&lt;h3&gt;Step 2: Weather View Controller&lt;/h3&gt;&lt;p&gt;After receiving a response from the Forecast API, we need to store it so that we can use it later to update the view. Create two private properties in &lt;strong&gt;MTWeatherViewController.m&lt;/strong&gt;, (1) &lt;code&gt;response&lt;/code&gt; (of type &lt;code&gt;NSDictionary&lt;/code&gt;) that will hold the response of the Forecast API and (2) &lt;code&gt;forecast&lt;/code&gt; (of type &lt;code&gt;NSArray&lt;/code&gt;) that will hold a subset of the response, the weather data for the next hours.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;quot;MTWeatherViewController.h&amp;quot;
#import &amp;quot;MTForecastClient.h&amp;quot;
@interface MTWeatherViewController () &amp;lt;CLLocationManagerDelegate&amp;gt; {
    BOOL _locationFound;
}
@property (strong, nonatomic) NSDictionary *location;
@property (strong, nonatomic) NSDictionary *response;
@property (strong, nonatomic) NSArray *forecast;
@property (strong, nonatomic) CLLocationManager *locationManager;
@end
&lt;/pre&gt;&lt;p&gt;To receive notifications, we need to update &lt;code&gt;initWithNibName:bundle:&lt;/code&gt; as shown below (&lt;strong&gt;MTWeatherViewController.m&lt;/strong&gt;). In &lt;code&gt;weatherDataDidChangeChange:&lt;/code&gt;, we store the response of the Forecast API in &lt;code&gt;response&lt;/code&gt; and &lt;code&gt;forecast&lt;/code&gt; and we update the view controller&amp;#8217;s view. In &lt;code&gt;temperatureUnitDidChange&lt;/code&gt;, we only need to update the view to reflect the changed setting.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Initialize Location Manager
        self.locationManager = [[CLLocationManager alloc] init];
        // Configure Location Manager
        [self.locationManager setDelegate:self];
        [self.locationManager setDesiredAccuracy:kCLLocationAccuracyKilometer];
        // Add Observer
        NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
        [nc addObserver:self selector:@selector(applicationDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
        [nc addObserver:self selector:@selector(reachabilityStatusDidChange:) name:MTRainReachabilityStatusDidChangeNotification object:nil];
        [nc addObserver:self selector:@selector(weatherDataDidChangeChange:) name:MTRainWeatherDataDidChangeChangeNotification object:nil];
        [nc addObserver:self selector:@selector(temperatureUnitDidChange:) name:MTRainTemperatureUnitDidChangeNotification object:nil];
    }
    return self;
}
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)weatherDataDidChangeChange:(NSNotification *)notification {
    // Update Response &amp;amp; Forecast
    [self setResponse:[notification userInfo]];
    [self setForecast:self.response[@&amp;quot;hourly&amp;quot;][@&amp;quot;data&amp;quot;]];
    // Update View
    [self updateView];
}
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)temperatureUnitDidChange:(NSNotification *)notification {
    // Update View
    [self updateView];
}
&lt;/pre&gt;&lt;h3&gt;Step 3: Forecast View Controller&lt;/h3&gt;&lt;p&gt;The steps are almost identical in the &lt;code&gt;MTForecastViewController&lt;/code&gt; class. We update &lt;code&gt;initWithNibName:bundle:&lt;/code&gt; as shown below, create two properties (&lt;code&gt;response&lt;/code&gt; and &lt;code&gt;forecast&lt;/code&gt;), and implement &lt;code&gt;weatherDataDidChangeChange:&lt;/code&gt; and &lt;code&gt;temperatureUnitDidChange:&lt;/code&gt;. The difference is the weather data stored in &lt;code&gt;forecast&lt;/code&gt;. We will implement &lt;code&gt;updateView&lt;/code&gt; a bit later in this tutorial, but it is good practice to create a stub implementation to get rid of any compiler warnings.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Add Observer
        NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
        [nc addObserver:self selector:@selector(weatherDataDidChangeChange:) name:MTRainWeatherDataDidChangeChangeNotification object:nil];
        [nc addObserver:self selector:@selector(temperatureUnitDidChange:) name:MTRainTemperatureUnitDidChangeNotification object:nil];
    }
    return self;
}
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;quot;MTForecastViewController.h&amp;quot;
@interface MTForecastViewController ()
@property (strong, nonatomic) NSDictionary *response;
@property (strong, nonatomic) NSArray *forecast;
@end
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)weatherDataDidChangeChange:(NSNotification *)notification {
    // Update Response &amp;amp; Forecast
    [self setResponse:[notification userInfo]];
    [self setForecast:self.response[@&amp;quot;daily&amp;quot;][@&amp;quot;data&amp;quot;]];
    // Update View
    [self updateView];
}
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)temperatureUnitDidChange:(NSNotification *)notification {
    // Update View
    [self updateView];
}
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)updateView {
}
&lt;/pre&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;2.&lt;/span&gt;User Interface Center View&lt;/h2&gt;&lt;h3&gt;Step 1: Outlets and Actions&lt;/h3&gt;&lt;p&gt;Even though the center view contains a lot of information, it isn&amp;#8217;t that difficult to implement. Let&amp;#8217;s start by creating a number of outlets and one new action. Update &lt;strong&gt;MTWeatherViewController.h&lt;/strong&gt; as shown below. Revisit Chris&amp;#8217;s design to better understand the location and purpose of each user interface element. The difference with Chris&amp;#8217;s design is that we will replace the calendar icon in the top right with the refresh button that we created in the previous tutorial. The weather data for the next hours will be presented in a collection view, which implies that the &lt;code&gt;MTWeatherViewController&lt;/code&gt; class needs to conform to the &lt;code&gt;UICollectionViewDataSource&lt;/code&gt;, &lt;code&gt;UICollectionViewDelegate&lt;/code&gt;, and &lt;code&gt;UICollectionViewDelegateFlowLayout&lt;/code&gt; protocols.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;lt;UIKit/UIKit.h&amp;gt;
#import &amp;quot;MTLocationsViewController.h&amp;quot;
@interface MTWeatherViewController : UIViewController &amp;lt;UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout, MTLocationsViewControllerDelegate&amp;gt;
@property (weak, nonatomic) IBOutlet UIButton *buttonLocation;
@property (weak, nonatomic) IBOutlet UIButton *buttonRefresh;
@property (weak, nonatomic) IBOutlet UILabel *labelDate;
@property (weak, nonatomic) IBOutlet UILabel *labelTemp;
@property (weak, nonatomic) IBOutlet UILabel *labelTime;
@property (weak, nonatomic) IBOutlet UILabel *labelWind;
@property (weak, nonatomic) IBOutlet UILabel *labelRain;
@property (weak, nonatomic) IBOutlet UILabel *labelLocation;
@property (weak, nonatomic) IBOutlet UICollectionView *collectionView;
@end
&lt;/pre&gt;&lt;p&gt;We also need to add an action for the location button in the top left. Open &lt;strong&gt;MTWeatherViewController.m&lt;/strong&gt; and add a new action named &lt;code&gt;openLeftView:&lt;/code&gt;. In &lt;code&gt;openLeftView:&lt;/code&gt;, we tell the view controller&amp;#8217;s view deck controller to toggle the left view. Remember that it is also possible to swipe from left to right to open the left view.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (IBAction)openLeftView:(id)sender {
    [self.viewDeckController toggleLeftViewAnimated:YES];
}
&lt;/pre&gt;&lt;h3&gt;Step 2: Creating the User Interface&lt;/h3&gt;&lt;p&gt;Open &lt;strong&gt;MTWeatherViewController.xib&lt;/strong&gt; and create the user interface as shown in figure 2. While creating the user interface, it is important to verify that the user interface displays correctly on both the 3.5&amp;#8243; screen and the iPhone 5&amp;#8242;s 4&amp;#8243; screen. You can test this by selecting the view controller&amp;#8217;s view and changing the &lt;strong&gt;Size&lt;/strong&gt; attribute in the &lt;strong&gt;Attributes Inspector&lt;/strong&gt;. To accomplish the desired result, you need to tweak the autolayout constraints of the user interface elements. The goal is to make the weather data stick to the top of the view, while the collection view is glued to the bottom. The icons next to the time, wind, and rain labels are instances of &lt;code&gt;UIImageView&lt;/code&gt;.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130530-2.png" alt="Create a Weather App with Forecast – User Interface - Creating the User Interface of the Weather View Controller " /&gt;&lt;br
/&gt; &lt;/figure&gt; &lt;figcaption&gt;Figure 2: Creating the User Interface of the Weather View Controller&lt;/figcaption&gt;&lt;p&gt;Configure the labels and buttons as shown in figure 2. This includes properly aligning the text of the labels, setting the types of both buttons to &lt;strong&gt;Custom&lt;/strong&gt;, making the &lt;strong&gt;File&amp;#8217;s Owner&lt;/strong&gt; the collection view&amp;#8217;s &lt;code&gt;dataSource&lt;/code&gt; and &lt;code&gt;delegate&lt;/code&gt;, and setting the scroll direction of the collection view flow layout to horizontal. I am a fan of &lt;strong&gt;Gill Sans&lt;/strong&gt; so that is the font I chose to use for this project. Before switching back to the implementation file of the weather view controller, connect the outlets and action that we created earlier. In addition to the labels and buttons, I&amp;#8217;ve also added an image view to the view controller&amp;#8217;s view to display the background image.&lt;/p&gt;&lt;p&gt;As I mentioned in the introduction, you can find the application&amp;#8217;s artwork in the source files of this tutorial. Create a folder named &lt;strong&gt;Artwork&lt;/strong&gt; in your Xcode project and drag the artwork in this folder.&lt;/p&gt;&lt;h3&gt;Step 3: Populating the User Interface&lt;/h3&gt;&lt;p&gt;We currently log the response of the Forecast API to Xcode&amp;#8217;s Console. To start using the weather data, we need to update the &lt;code&gt;fetchWeatherData&lt;/code&gt; method as shown below. In the completion block of &lt;code&gt;requestWeatherForCoordinate:completion:&lt;/code&gt;, we hide the progress HUD and send a notification on the main thread. We make use of the &lt;code&gt;dispatch_async&lt;/code&gt; function and pass the queue of the main thread as the first argument. The notification&amp;#8217;s &lt;code&gt;userInfo&lt;/code&gt; dictionary is the response of the request.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)fetchWeatherData {
    if ([[MTForecastClient sharedClient] networkReachabilityStatus] == AFNetworkReachabilityStatusNotReachable) return;
    // Show Progress HUD
    [SVProgressHUD showWithMaskType:SVProgressHUDMaskTypeGradient];
    // Query Forecast API
    double lat = [[_location objectForKey:MTLocationKeyLatitude] doubleValue];
    double lng = [[_location objectForKey:MTLocationKeyLongitude] doubleValue];
    [[MTForecastClient sharedClient] requestWeatherForCoordinate:CLLocationCoordinate2DMake(lat, lng) completion:^(BOOL success, NSDictionary *response) {
        // Dismiss Progress HUD
        [SVProgressHUD dismiss];
        if (response &amp;amp;&amp;amp; [response isKindOfClass:[NSDictionary class]]) {
            dispatch_async(dispatch_get_main_queue(), ^{
                // Post Notification on Main Thread
                NSNotification *notification = [NSNotification notificationWithName:MTRainWeatherDataDidChangeChangeNotification object:nil userInfo:response];
                [[NSNotificationCenter defaultCenter] postNotification:notification];
            });
        }
    }];
}
&lt;/pre&gt;&lt;p&gt;The weather and forecast view controllers are both observers of &lt;code&gt;MTRainWeatherDataDidChangeChangeNotification&lt;/code&gt; notifications. The weather view controller invokes &lt;code&gt;weatherDataDidChangeChange:&lt;/code&gt;, which in turn invokes &lt;code&gt;updateView&lt;/code&gt;. In &lt;code&gt;updateView&lt;/code&gt;, we invoke &lt;code&gt;updateCurrentWeather&lt;/code&gt; and update the collection view by sending it a message of &lt;code&gt;reloadData&lt;/code&gt;.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)updateView {
    // Update Location Label
    [self.labelLocation setText:[self.location objectForKey:MTLocationKeyCity]];
    // Update Current Weather
    [self updateCurrentWeather];
    // Reload Collection View
    [self.collectionView reloadData];
}
&lt;/pre&gt;&lt;p&gt;Before we implement &lt;code&gt;updateCurrentWeather&lt;/code&gt;, I want to take a small detour. We will be displaying temperature values in various places of the application and because we support both Fahrenheit and Celsius this can become cumbersome. It is therefore useful to create a class that centralizes this logic so that we don&amp;#8217;t need to clutter our code base with if statements and temperature conversions.&lt;/p&gt;&lt;h3&gt;Step 4: Creating the Settings Class&lt;/h3&gt;&lt;p&gt;Before we create the class that handles temperature conversions, we need to be able to store the current temperature setting in the user defaults database. Revisit &lt;strong&gt;MTConstants.h/.m&lt;/strong&gt; and declare a string constant with a name of &lt;code&gt;MTRainUserDefaultsTemperatureUnit&lt;/code&gt;.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
extern NSString * const MTRainUserDefaultsTemperatureUnit;
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
NSString * const MTRainUserDefaultsTemperatureUnit = @&amp;quot;temperatureUnit&amp;quot;;
&lt;/pre&gt;&lt;p&gt;To make working with settings easier, I often create a category on &lt;code&gt;NSUserDefaults&lt;/code&gt; that allows me to quickly and elegantly access the application&amp;#8217;s settings. Let me show you what I mean. Create a new Objective-C category (figure 3), name the category &lt;strong&gt;Helpers&lt;/strong&gt;, and make it a category on &lt;code&gt;NSUserDefaults&lt;/code&gt; (figure 4). In &lt;strong&gt;NSUserDefaults+Helpers.h&lt;/strong&gt;, we declare three class methods as shown below.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130530-3.png" alt="Create a Weather App with Forecast – User Interface - Creating a New Objective-C Category " /&gt;&lt;br
/&gt; &lt;/figure&gt; &lt;figcaption&gt;Figure 3: Creating a New Objective-C Category&lt;/figcaption&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130530-4.png" alt="Create a Weather App with Forecast – User Interface - Creating a Category on NSUserDefaults " /&gt;&lt;br
/&gt; &lt;/figure&gt; &lt;figcaption&gt;Figure 4: Creating a Category on NSUserDefaults&lt;/figcaption&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;lt;Foundation/Foundation.h&amp;gt;
@interface NSUserDefaults (Helpers)
#pragma mark -
#pragma mark Temperature
+ (BOOL)isDefaultCelcius;
+ (void)setDefaultToCelcius;
+ (void)setDefaultToFahrenheit;
@end
&lt;/pre&gt;&lt;p&gt;Even though these methods aren&amp;#8217;t magical, they are very useful. The first method, &lt;code&gt;isDefaultCelcius&lt;/code&gt;, tells us if the temperature unit is set to Celsius or not. The other two methods make it very easy to switch between Fahrenheit and Celsius. Not only do we update the user defaults database, we also post a notification that informs observers of the change.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
+ (BOOL)isDefaultCelcius {
    return [[NSUserDefaults standardUserDefaults] integerForKey:MTRainUserDefaultsTemperatureUnit] == 1;
}
+ (void)setDefaultToCelcius {
    // Update User Defaults
    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
    [ud setInteger:1 forKey:MTRainUserDefaultsTemperatureUnit];
    [ud synchronize];
    // Post Notification
    [[NSNotificationCenter defaultCenter] postNotificationName:MTRainTemperatureUnitDidChangeNotification object:nil];
}
+ (void)setDefaultToFahrenheit {
    // Update User Defaults
    NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
    [ud setInteger:0 forKey:MTRainUserDefaultsTemperatureUnit];
    [ud synchronize];
    // Post Notification
    [[NSNotificationCenter defaultCenter] postNotificationName:MTRainTemperatureUnitDidChangeNotification object:nil];
}
&lt;/pre&gt;&lt;p&gt;It is time to create the settings class that I wrote about earlier. The solution is surprisingly easy. Create a new Objective-C class, name it &lt;code&gt;MTSettings&lt;/code&gt;, and make it a subclass of &lt;code&gt;NSObject&lt;/code&gt; (figure 5). In &lt;strong&gt;MTSettings.h&lt;/strong&gt;, we declare one class method, &lt;code&gt;formatTemperature:&lt;/code&gt;. In &lt;strong&gt;MTSettings.m&lt;/strong&gt;, we import the header of the category we created a moment ago and implement &lt;code&gt;formatTemperature:&lt;/code&gt; as shown below. The method accepts an instance of &lt;code&gt;NSNumber&lt;/code&gt;, converts it to a float, and returns a formatted string based on the temperature setting.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130530-5.png" alt="Create a Weather App with Forecast – User Interface - Creating the MTSettings Class " /&gt;&lt;br
/&gt; &lt;/figure&gt; &lt;figcaption&gt;Figure 5: Creating the MTSettings Class&lt;/figcaption&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;lt;Foundation/Foundation.h&amp;gt;
@interface MTSettings : NSObject
#pragma mark -
#pragma mark Convenience Methods
+ (NSString *)formatTemperature:(NSNumber *)temperature;
@end
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;quot;NSUserDefaults+Helpers.h&amp;quot;
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
+ (NSString *)formatTemperature:(NSNumber *)temperature {
    float value = [temperature floatValue];
    if ([NSUserDefaults isDefaultCelcius]) {
        value = (value  -  32.0)  *  (5.0 / 9.0);
    }
    return [NSString stringWithFormat:@&amp;quot;%.0f°&amp;quot;, value];
}
&lt;/pre&gt;&lt;p&gt;Before we continue, add an import statement for the &lt;code&gt;MTSettings&lt;/code&gt; class to the project&amp;#8217;s precompiled header file so that we can use it throughout the project.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;lt;Availability.h&amp;gt;
#ifndef __IPHONE_3_0
#warning &amp;quot;This project uses features only available in iOS SDK 3.0 and later.&amp;quot;
#endif
#ifdef __OBJC__
    #import &amp;lt;UIKit/UIKit.h&amp;gt;
    #import &amp;lt;Foundation/Foundation.h&amp;gt;
    #import &amp;lt;QuartzCore/QuartzCore.h&amp;gt;
    #import &amp;lt;CoreLocation/CoreLocation.h&amp;gt;
    #import &amp;lt;MobileCoreServices/MobileCoreServices.h&amp;gt;
    #import &amp;lt;SystemConfiguration/SystemConfiguration.h&amp;gt;
    #import &amp;quot;AFNetworking.h&amp;quot;
    #import &amp;quot;SVProgressHUD.h&amp;quot;
    #import &amp;quot;IIViewDeckController.h&amp;quot;
    #import &amp;quot;MTSettings.h&amp;quot;
    #import &amp;quot;MTConstants.h&amp;quot;
#endif
&lt;/pre&gt;&lt;p&gt;It is now time to implement &lt;code&gt;updateCurrentWeather&lt;/code&gt; in the &lt;code&gt;MTWeatherViewController&lt;/code&gt; class. The data for the current weather is a subset of the response we received from the Forecast API. The implementation of &lt;code&gt;updateCurrentWeather&lt;/code&gt; is pretty straightforward. The only caveat to watch out for is the precipitation probability. If this value is equal to &lt;code&gt;0&lt;/code&gt;, the key &lt;code&gt;precipProbability&lt;/code&gt; is not included in the response. That is the reason that we first check for the existence of the key &lt;code&gt;precipProbability&lt;/code&gt; in the response dictionary.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)updateCurrentWeather {
    // Weather Data
    NSDictionary *data = [self.response objectForKey:@&amp;quot;currently&amp;quot;];
    // Update Date Label
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
    [dateFormatter setDateFormat:@&amp;quot;EEEE, MMM d&amp;quot;];
    NSDate *date = [NSDate dateWithTimeIntervalSince1970:[data[@&amp;quot;time&amp;quot;] doubleValue]];
    [self.labelDate setText:[dateFormatter stringFromDate:date]];
    // Update Temperature Label
    [self.labelTemp setText:[MTSettings formatTemperature:data[@&amp;quot;temperature&amp;quot;]]];
    // Update Time Label
    NSDateFormatter *timeFormatter = [[NSDateFormatter alloc] init];
    [timeFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
    [timeFormatter setDateFormat:@&amp;quot;ha&amp;quot;];
    [self.labelTime setText:[timeFormatter stringFromDate:[NSDate date]]];
    // Update Wind Label
    [self.labelWind setText:[NSString stringWithFormat:@&amp;quot;%.0fMP&amp;quot;, [data[@&amp;quot;windSpeed&amp;quot;] floatValue]]];
    // Update Rain Label
    float rainProbability = 0.0;
    if (data[@&amp;quot;precipProbability&amp;quot;]) {
        rainProbability = [data[@&amp;quot;precipProbability&amp;quot;] floatValue] * 100.0;
    }
    [self.labelRain setText:[NSString stringWithFormat:@&amp;quot;%.0f%%&amp;quot;, rainProbability]];
}
&lt;/pre&gt;&lt;h3&gt;Step 5: Populating the Collection View&lt;/h3&gt;&lt;p&gt;To populate the collection view, we first need to create a &lt;code&gt;UICollectionViewCell&lt;/code&gt; subclass. Create a new Objective-C class, name it &lt;code&gt;MTHourCell&lt;/code&gt;, and make it a subclass of &lt;code&gt;UICollectionViewCell&lt;/code&gt; (figure 6). Creating custom table or collection view cells can be laborious and painstaking. If you want to learn more about creating custom table and collection view cells, then I suggest you take a look at &lt;a
href="http://mobile.tutsplus.com/tutorials/iphone/customizing-uitableview-cell/"&gt;a tutorial&lt;/a&gt; I wrote a few weeks ago.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130530-6.png" alt="Create a Weather App with Forecast – User Interface - Creating a Custom Collection View " /&gt;&lt;br
/&gt; &lt;/figure&gt; &lt;figcaption&gt;Figure 6: Creating a Custom Collection View&lt;/figcaption&gt;&lt;p&gt;In the interface of &lt;code&gt;MTHourCell&lt;/code&gt;, we declare four properties of type &lt;code&gt;UILabel&lt;/code&gt;. We don&amp;#8217;t do much magic in &lt;strong&gt;MTHourcell.m&lt;/strong&gt; as you can see below. To better understand the &lt;code&gt;initWithFrame:&lt;/code&gt; method, revisit the design I showed you at the beginning of this article. I won&amp;#8217;t discuss the implementation of &lt;code&gt;initWithFrame:&lt;/code&gt; in detail, but I do want to point out that I use a preprocessor define for the text color of the labels. I added the preprocess define to &lt;strong&gt;MTConstants.h&lt;/strong&gt; to make it available to the entire project (see below).&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;lt;UIKit/UIKit.h&amp;gt;
@interface MTHourCell : UICollectionViewCell
@property (strong, nonatomic) UILabel *labelTime;
@property (strong, nonatomic) UILabel *labelTemp;
@property (strong, nonatomic) UILabel *labelWind;
@property (strong, nonatomic) UILabel *labelRain;
@end
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;quot;MTHourCell.h&amp;quot;
#define kMTLabelBottomWidth 40.0
#define kMTLabelBottomHeight 40.0
@interface MTHourCell ()
@end
@implementation MTHourCell
- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];
    if (self) {
        // Helpers
        CGSize size = self.contentView.frame.size;
        // Initialize Label Time
        self.labelTime = [[UILabel alloc] initWithFrame:CGRectMake(30.0, 0.0, 50.0, 40.0)];
        // Configure Label Time
        [self.labelTime setBackgroundColor:[UIColor clearColor]];
        [self.labelTime setTextColor:[UIColor whiteColor]];
        [self.labelTime setFont:[UIFont fontWithName:@&amp;quot;GillSans-Light&amp;quot; size:18.0]];
        [self.labelTime setAutoresizingMask:(UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleBottomMargin)];
        [self.contentView addSubview:self.labelTime];
        // Initialize Label Temp
        self.labelTemp = [[UILabel alloc] initWithFrame:CGRectMake(0.0, 46.0, 80.0, 44.0)];
        // Configure Label Temp
        [self.labelTemp setBackgroundColor:[UIColor clearColor]];
        [self.labelTemp setTextAlignment:NSTextAlignmentCenter];
        [self.labelTemp setTextColor:kMTColorGray];
        [self.labelTemp setFont:[UIFont fontWithName:@&amp;quot;GillSans-Bold&amp;quot; size:40.0]];
        [self.labelTemp setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin)];
        [self.contentView addSubview:self.labelTemp];
        // Initialize Label Wind
        self.labelWind = [[UILabel alloc] initWithFrame:CGRectMake(0.0, size.height - kMTLabelBottomHeight, kMTLabelBottomWidth, kMTLabelBottomHeight)];
        // Configure Label Wind
        [self.labelWind setBackgroundColor:[UIColor clearColor]];
        [self.labelWind setTextAlignment:NSTextAlignmentCenter];
        [self.labelWind setTextColor:kMTColorGray];
        [self.labelWind setFont:[UIFont fontWithName:@&amp;quot;GillSans-Light&amp;quot; size:16.0]];
        [self.labelWind setAutoresizingMask:(UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin)];
        [self.contentView addSubview:self.labelWind];
        // Initialize Label Rain
        self.labelRain = [[UILabel alloc] initWithFrame:CGRectMake(size.width - kMTLabelBottomWidth, size.height - kMTLabelBottomHeight, kMTLabelBottomWidth, kMTLabelBottomHeight)];
        // Configure Label Rain
        [self.labelRain setBackgroundColor:[UIColor clearColor]];
        [self.labelRain setTextAlignment:NSTextAlignmentCenter];
        [self.labelRain setTextColor:kMTColorGray];
        [self.labelRain setFont:[UIFont fontWithName:@&amp;quot;GillSans-Light&amp;quot; size:16.0]];
        [self.labelRain setAutoresizingMask:(UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin)];
        [self.contentView addSubview:self.labelRain];
        // Background View
        UIImage *backgroundImage = [[UIImage imageNamed:@&amp;quot;background-hour-cell&amp;quot;] resizableImageWithCapInsets:UIEdgeInsetsMake(40.0, 10.0, 10.0, 10.0)];
        UIImageView *backgroundView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, size.width, size.height)];
        [backgroundView setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
        [backgroundView setImage:backgroundImage];
        [self setBackgroundView:backgroundView];
    }
    return self;
}
@end
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
#define kMTColorGray [UIColor colorWithRed:0.737 green:0.737 blue:0.737 alpha:1.0]
#define kMTColorGreen [UIColor colorWithRed:0.325 green:0.573 blue:0.388 alpha:1.0]
#define kMTColorOrange [UIColor colorWithRed:1.000 green:0.306 blue:0.373 alpha:1.0]
&lt;/pre&gt;&lt;p&gt;As you can see below, implementing the &lt;code&gt;UICollectionViewDataSource&lt;/code&gt;, &lt;code&gt;UICollectionViewDelegate&lt;/code&gt;, and &lt;code&gt;UICollectionViewDelegateFlowLayout&lt;/code&gt; protocols is very similar to implementing the &lt;code&gt;UITableViewDataSource&lt;/code&gt; and &lt;code&gt;UITableViewDelegate&lt;/code&gt; protocols.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    return self.forecast ? 1 : 0;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    return [self.forecast count];
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
    MTHourCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:HourCell forIndexPath:indexPath];
    // Fetch Data
    NSDictionary *data = [self.forecast objectAtIndex:indexPath.row];
    // Initialize Date Formatter
    NSDateFormatter *timeFormatter = [[NSDateFormatter alloc] init];
    [timeFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
    [timeFormatter setDateFormat:@&amp;quot;ha&amp;quot;];
    NSDate *date = [NSDate dateWithTimeIntervalSince1970:[data[@&amp;quot;time&amp;quot;] doubleValue]];
    // Configure Cell
    [cell.labelTime setText:[timeFormatter stringFromDate:date]];
    [cell.labelTemp setText:[MTSettings formatTemperature:data[@&amp;quot;temperature&amp;quot;]]];
    [cell.labelWind setText:[NSString stringWithFormat:@&amp;quot;%.0fMP&amp;quot;, [data[@&amp;quot;windSpeed&amp;quot;] floatValue]]];
    float rainProbability = 0.0;
    if (data[@&amp;quot;precipProbability&amp;quot;]) {
        rainProbability = [data[@&amp;quot;precipProbability&amp;quot;] floatValue] * 100.0;
    }
    [cell.labelRain setText:[NSString stringWithFormat:@&amp;quot;%.0f%%&amp;quot;, rainProbability]];
    return cell;
}
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    return CGSizeMake(80.0, 120.0);
}
- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout insetForSectionAtIndex:(NSInteger)section {
    return UIEdgeInsetsMake(0.0, 10.0, 0.0, 10.0);
}
&lt;/pre&gt;&lt;p&gt;To make all this work, we need to (1) import the header file of &lt;code&gt;MTHourCell&lt;/code&gt;, (2) declare a static string constant that serves as the cell reuse identifier, and (3) tell the collection view to use the &lt;code&gt;MTHourCell&lt;/code&gt; class to instantiate new cells. In &lt;code&gt;viewDidLoad&lt;/code&gt;, we also set the collection view&amp;#8217;s background color to transparant.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;quot;MTHourCell.h&amp;quot;
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
static NSString *HourCell = @&amp;quot;HourCell&amp;quot;;
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)viewDidLoad {
    [super viewDidLoad];
    // Load Location
    self.location = [[NSUserDefaults standardUserDefaults] objectForKey:MTRainUserDefaultsLocation];
    if (!self.location) {
        [self.locationManager startUpdatingLocation];
    }
    // Configure Collection View
    [self.collectionView setBackgroundColor:[UIColor clearColor]];
    [self.collectionView registerClass:[MTHourCell class] forCellWithReuseIdentifier:HourCell];
}
&lt;/pre&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;3.&lt;/span&gt;User Interface Right View&lt;/h2&gt;&lt;h3&gt;Step 1: Outlets&lt;/h3&gt;&lt;p&gt;Even though the right view displays a lot of data, the implementation of the &lt;code&gt;MTForecastViewController&lt;/code&gt; class isn&amp;#8217;t that complex. We start by creating an outlet for the table view in &lt;strong&gt;MTForecastViewController.h&lt;/strong&gt; and conform the class to the &lt;code&gt;UITableViewDataSource&lt;/code&gt; and &lt;code&gt;UITableViewDelegate&lt;/code&gt; protocols.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;lt;UIKit/UIKit.h&amp;gt;
@interface MTForecastViewController : UIViewController &amp;lt;UITableViewDataSource, UITableViewDelegate&amp;gt;
@property (weak, nonatomic) IBOutlet UITableView *tableView;
@end
&lt;/pre&gt;&lt;h3&gt;Step 2: Creating the User Interface&lt;/h3&gt;&lt;p&gt;Creating the user interface is as simple as adding a table view to the view controller&amp;#8217;s view, connecting the outlet we created a moment ago, and setting the &lt;strong&gt;File&amp;#8217;s Owner&lt;/strong&gt; as the table view&amp;#8217;s &lt;code&gt;dataSource&lt;/code&gt; and &lt;code&gt;delegate&lt;/code&gt; (figure 7).&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130530-7.png" alt="Create a Weather App with Forecast – User Interface - Creating the User Interface of the Forecast View Controller " /&gt;&lt;br
/&gt; &lt;/figure&gt; &lt;figcaption&gt;Figure 7: Creating the User Interface of the Forecast View Controller&lt;/figcaption&gt;&lt;h3&gt;Step 3: Populating the Table View&lt;/h3&gt;&lt;p&gt;Before we populate the table view with data, we need to create a &lt;code&gt;UITableViewCell&lt;/code&gt; subclass. Create a new Objective-C class, name it &lt;code&gt;MTDayCell&lt;/code&gt;, and make it a subclass of &lt;code&gt;UITableViewCell&lt;/code&gt; (figure 8). Open &lt;strong&gt;MTDayCell.h&lt;/strong&gt; and declare five outlets of type &lt;code&gt;UILabel&lt;/code&gt;. As with the &lt;code&gt;MTHourCell&lt;/code&gt; class, the implementation of &lt;code&gt;MTDayCell&lt;/code&gt; isn&amp;#8217;t too difficult as you can see below.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130530-8.png" alt="Create a Weather App with Forecast – User Interface - Creating a Custom Table View Cell " /&gt;&lt;br
/&gt; &lt;/figure&gt; &lt;figcaption&gt;Figure 8: Creating a Custom Table View Cell&lt;/figcaption&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;lt;UIKit/UIKit.h&amp;gt;
@interface MTDayCell : UITableViewCell
@property (strong, nonatomic) UILabel *labelDay;
@property (strong, nonatomic) UILabel *labelDate;
@property (strong, nonatomic) UILabel *labelTemp;
@property (strong, nonatomic) UILabel *labelWind;
@property (strong, nonatomic) UILabel *labelRain;
@end
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;quot;MTDayCell.h&amp;quot;
#define kMTCalendarWidth 44.0
#define kMTCalendarHeight 80.0
#define kMTCalendarMarginLeft 60.0
#define kMTLabelRightWidth 30.0
#define kMTLabelRightHeight 14.0
@interface MTDayCell ()
@property (strong, nonatomic) UIImageView *imageViewCalendar;
@end
@implementation MTDayCell
#pragma mark -
#pragma mark Initialization
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        // Helpers
        CGSize size = self.contentView.frame.size;
        // Configure Table View Cell
        [self setSelectionStyle:UITableViewCellSelectionStyleNone];
        // Initialize Image View Clock
        self.imageViewCalendar = [[UIImageView alloc] initWithFrame:CGRectMake(kMTCalendarMarginLeft, 0.0, kMTCalendarWidth, kMTCalendarHeight)];
        // Configure Image View Clock
        [self.imageViewCalendar setContentMode:UIViewContentModeCenter];
        [self.imageViewCalendar setImage:[UIImage imageNamed:@&amp;quot;background-calendar-day-cell&amp;quot;]];
        [self.imageViewCalendar setAutoresizingMask:(UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin)];
        [self.contentView addSubview:self.imageViewCalendar];
        // Initialize Label Day
        self.labelDay = [[UILabel alloc] initWithFrame:CGRectMake(kMTCalendarMarginLeft, 10.0, kMTCalendarWidth, 20.0)];
        // Configure Label Day
        [self.labelDay setTextColor:[UIColor whiteColor]];
        [self.labelDay setTextAlignment:NSTextAlignmentCenter];
        [self.labelDay setBackgroundColor:[UIColor clearColor]];
        [self.labelDay setFont:[UIFont fontWithName:@&amp;quot;GillSans&amp;quot; size:14.0]];
        [self.labelDay setAutoresizingMask:(UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin)];
        [self.contentView addSubview:self.labelDay];
        // Initialize Label Date
        self.labelDate = [[UILabel alloc] initWithFrame:CGRectMake(kMTCalendarMarginLeft, 20.0, kMTCalendarWidth, 60.0)];
        // Configure Label Date
        [self.labelDate setTextColor:kMTColorGray];
        [self.labelDate setTextAlignment:NSTextAlignmentCenter];
        [self.labelDate setBackgroundColor:[UIColor clearColor]];
        [self.labelDate setFont:[UIFont fontWithName:@&amp;quot;GillSans&amp;quot; size:24.0]];
        [self.labelDate setAutoresizingMask:(UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin)];
        [self.contentView addSubview:self.labelDate];
        // Initialize Label Wind
        self.labelWind = [[UILabel alloc] initWithFrame:CGRectMake(size.width - kMTLabelRightWidth, (size.height / 2.0) - kMTLabelRightHeight, kMTLabelRightWidth, kMTLabelRightHeight)];
        // Configure Label Wind
        [self.labelWind setTextColor:kMTColorGray];
        [self.labelWind setTextAlignment:NSTextAlignmentCenter];
        [self.labelWind setBackgroundColor:[UIColor clearColor]];
        [self.labelWind setFont:[UIFont fontWithName:@&amp;quot;GillSans&amp;quot; size:12.0]];
        [self.labelWind setAutoresizingMask:(UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleTopMargin)];
        [self.contentView addSubview:self.labelWind];
        // Initialize Label Rain
        self.labelRain = [[UILabel alloc] initWithFrame:CGRectMake(size.width - kMTLabelRightWidth, (size.height / 2.0), kMTLabelRightWidth, kMTLabelRightHeight)];
        // Configure Label Rain
        [self.labelRain setTextColor:kMTColorGray];
        [self.labelRain setTextAlignment:NSTextAlignmentCenter];
        [self.labelRain setBackgroundColor:[UIColor clearColor]];
        [self.labelRain setFont:[UIFont fontWithName:@&amp;quot;GillSans&amp;quot; size:12.0]];
        [self.labelRain setAutoresizingMask:(UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin)];
        [self.contentView addSubview:self.labelRain];
        // Initialize Label Temp
        self.labelTemp = [[UILabel alloc] initWithFrame:CGRectMake(kMTCalendarWidth + kMTCalendarMarginLeft + 12.0, 0.0, size.width - kMTCalendarWidth - kMTCalendarMarginLeft - kMTLabelRightWidth - 12.0, size.height)];
        // Configure Label Temp
        [self.labelTemp setTextColor:kMTColorGray];
        [self.labelTemp setTextAlignment:NSTextAlignmentCenter];
        [self.labelTemp setBackgroundColor:[UIColor clearColor]];
        [self.labelTemp setFont:[UIFont fontWithName:@&amp;quot;GillSans-Bold&amp;quot; size:40.0]];
        [self.labelTemp setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
        [self.contentView addSubview:self.labelTemp];
    }
    return self;
}
@end
&lt;/pre&gt;&lt;p&gt;The implementation of the table view data source protocol is very similar to that of the collection view data source protocol that we saw earlier. We also implement one method of the table view delegate protocol, &lt;code&gt;tableView:heightForRowAtIndexPath:&lt;/code&gt;, to set the row height to &lt;code&gt;80.0&lt;/code&gt;.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return self.forecast ? 1 : 0;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [self.forecast count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    MTDayCell *cell = [tableView dequeueReusableCellWithIdentifier:DayCell forIndexPath:indexPath];
    // Fetch Data
    NSDictionary *data = [self.forecast objectAtIndex:indexPath.row];
    // Initialize Date Formatter
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
    [dateFormatter setFormatterBehavior:NSDateFormatterBehavior10_4];
    NSDate *date = [NSDate dateWithTimeIntervalSince1970:[data[@&amp;quot;time&amp;quot;] doubleValue]];
    // Configure Cell
    [dateFormatter setDateFormat:@&amp;quot;EEE&amp;quot;];
    [cell.labelDay setText:[dateFormatter stringFromDate:date]];
    [dateFormatter setDateFormat:@&amp;quot;d&amp;quot;];
    [cell.labelDate setText:[dateFormatter stringFromDate:date]];
    float tempMin = [data[@&amp;quot;temperatureMin&amp;quot;] floatValue];
    float tempMax = [data[@&amp;quot;temperatureMax&amp;quot;] floatValue];
    [cell.labelTemp setText:[NSString stringWithFormat:@&amp;quot;%.0f°/%.0f°&amp;quot;, tempMin, tempMax]];
    [cell.labelWind setText:[NSString stringWithFormat:@&amp;quot;%.0f&amp;quot;, [data[@&amp;quot;windSpeed&amp;quot;] floatValue]]];
    float rainProbability = 0.0;
    if (data[@&amp;quot;precipProbability&amp;quot;]) {
        rainProbability = [data[@&amp;quot;precipProbability&amp;quot;] floatValue] * 100.0;
    }
    [cell.labelRain setText:[NSString stringWithFormat:@&amp;quot;%.0f&amp;quot;, rainProbability]];
    return cell;
}
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return 80.0;
}
&lt;/pre&gt;&lt;p&gt;To make all this work, we need to (1) import the header file of the &lt;code&gt;MTDayCell&lt;/code&gt; class, (2) declare a static string constant for the cell reuse identifier, and (3) register the &lt;code&gt;MTDayCell&lt;/code&gt; as the class for that cell reuse identifier in &lt;code&gt;viewDidLoad&lt;/code&gt;. In &lt;code&gt;updateView&lt;/code&gt;, we reload the table view.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;quot;MTDayCell.h&amp;quot;
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
static NSString *DayCell = @&amp;quot;DayCell&amp;quot;;
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)viewDidLoad {
    [super viewDidLoad];
    // Configure Table View
    [self.tableView registerClass:[MTDayCell class] forCellReuseIdentifier:DayCell];
}
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)updateView {
    // Reload Table View
    [self.tableView reloadData];
}
&lt;/pre&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;4.&lt;/span&gt;User Interface Right View&lt;/h2&gt;&lt;h3&gt;Step 1: Updating the User Interface&lt;/h3&gt;&lt;p&gt;It is clear that we need to make some significant changes to the locations view controller to implement Chris&amp;#8217;s design. The table view of the locations view controller will include two sections instead of one. The top section will display the stored locations while the bottom section is reserved for the temperature setting. Start by opening &lt;strong&gt;MTLocationsViewController.xib&lt;/strong&gt; and remove the navigation bar that we added in the previous article (figure 9). This means that we can also delete the outlet for the edit button in &lt;strong&gt;MTLocationsViewController.h&lt;/strong&gt; and the &lt;code&gt;editLocations&lt;/code&gt; action in &lt;strong&gt;MTLocationsViewController.m&lt;/strong&gt;.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130530-9.png" alt="Create a Weather App with Forecast – User Interface - Updating the User Interface of the Locations View Controller " /&gt;&lt;br
/&gt; &lt;/figure&gt;&lt;/p&gt; &lt;figcaption&gt;Figure 9: Updating the User Interface of the Locations View Controller&lt;/figcaption&gt;&lt;h3&gt;Step 2: Creating the Location Cell&lt;/h3&gt;&lt;p&gt;The cells that display the locations have a delete button on the left. To make this work, we need to create a custom table view cell. Create another &lt;code&gt;UITableViewCell&lt;/code&gt; subclass and name it &lt;code&gt;MTLocationCell&lt;/code&gt; (figure 10). Open &lt;strong&gt;MTLocationCell.h&lt;/strong&gt; and create two properties, (1) &lt;code&gt;buttonDelete&lt;/code&gt; (&lt;code&gt;UIButton&lt;/code&gt;) and (2) &lt;code&gt;labelLocation&lt;/code&gt; (&lt;code&gt;UILabel&lt;/code&gt;). As you can see, the implementation of &lt;code&gt;MTLocationCell&lt;/code&gt; is less complex than those of &lt;code&gt;MTHourCell&lt;/code&gt; and &lt;code&gt;MTDayCell&lt;/code&gt;.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/figure-20130530-10.png" alt="Create a Weather App with Forecast – User Interface - Creating a Custom Table View Cell " /&gt;&lt;br
/&gt; &lt;/figure&gt; &lt;figcaption&gt;Figure 10: Creating a Custom Table View Cell&lt;/figcaption&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;lt;UIKit/UIKit.h&amp;gt;
@interface MTLocationCell : UITableViewCell
@property (strong, nonatomic) UIButton *buttonDelete;
@property (strong, nonatomic) UILabel *labelLocation;
@end
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;quot;MTLocationCell.h&amp;quot;
#define kMTButtonDeleteWidth 44.0
#define kMTLabelLocationMarginLeft 44.0
@implementation MTLocationCell
#pragma mark -
#pragma mark Initialization
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        // Helpers
        CGSize size = self.contentView.frame.size;
        // Initialize Delete Button
        self.buttonDelete = [UIButton buttonWithType:UIButtonTypeCustom];
        // Configure Delete Button
        [self.buttonDelete setFrame:CGRectMake(0.0, 0.0, kMTButtonDeleteWidth, size.height)];
        [self.buttonDelete setImage:[UIImage imageNamed:@&amp;quot;button-delete-location-cell&amp;quot;] forState:UIControlStateNormal];
        [self.buttonDelete setImage:[UIImage imageNamed:@&amp;quot;button-delete-location-cell&amp;quot;] forState:UIControlStateSelected];
        [self.buttonDelete setImage:[UIImage imageNamed:@&amp;quot;button-delete-location-cell&amp;quot;] forState:UIControlStateDisabled];
        [self.buttonDelete setImage:[UIImage imageNamed:@&amp;quot;button-delete-location-cell&amp;quot;] forState:UIControlStateHighlighted];
        [self.buttonDelete setAutoresizingMask:(UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleRightMargin)];
        [self.contentView addSubview:self.buttonDelete];
        // Initialize Location Label
        self.labelLocation = [[UILabel alloc] initWithFrame:CGRectMake(kMTLabelLocationMarginLeft, 0.0, size.width - kMTLabelLocationMarginLeft, size.height)];
        // Configure Text Label
        [self.labelLocation setTextColor:kMTColorGray];
        [self.labelLocation setBackgroundColor:[UIColor clearColor]];
        [self.labelLocation setFont:[UIFont fontWithName:@&amp;quot;GillSans&amp;quot; size:20.0]];
        [self.labelLocation setAutoresizingMask:(UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleLeftMargin)];
        [self.contentView addSubview:self.labelLocation];
    }
    return self;
}
@end
&lt;/pre&gt;&lt;h3&gt;Step 3: Updating the Table View Data Source Protocol&lt;/h3&gt;&lt;p&gt;To implement the design, we need to update the &lt;code&gt;UITableViewDataSource&lt;/code&gt; and &lt;code&gt;UITableViewDelegate&lt;/code&gt; protocols. Start by importing the header file of the &lt;code&gt;MTLocationCell&lt;/code&gt; class and the category on &lt;code&gt;NSUserDefaults&lt;/code&gt; that we created earlier. The table view will contain three types of cells and we need to declare a reuse identifier for each type (see below).&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
#import &amp;quot;MTLocationsViewController.h&amp;quot;
#import &amp;quot;MTLocationCell.h&amp;quot;
#import &amp;quot;NSUserDefaults+Helpers.h&amp;quot;
@interface MTLocationsViewController ()
@property (strong, nonatomic) NSMutableArray *locations;
@end
&lt;/pre&gt;&lt;pre class="brush: objc; title: ;"&gt;
static NSString *AddLocationCell = @&amp;quot;AddLocationCell&amp;quot;;
static NSString *LocationCell = @&amp;quot;LocationCell&amp;quot;;
static NSString *SettingsCell = @&amp;quot;SettingsCell&amp;quot;;
&lt;/pre&gt;&lt;p&gt;In &lt;code&gt;setupView&lt;/code&gt;, we configure the table view by (1) setting its &lt;code&gt;separatorStyle&lt;/code&gt; property to &lt;code&gt;UITableViewCellSeparatorStyleNone&lt;/code&gt; and (2) registering a class for each reuse identifier.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)setupView {
    // Setup Table View
    [self.tableView setSeparatorStyle:UITableViewCellSeparatorStyleNone];
    // Register Class for Cell Reuse
    [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:AddLocationCell];
    [self.tableView registerClass:[MTLocationCell class] forCellReuseIdentifier:LocationCell];
    [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:SettingsCell];
}
&lt;/pre&gt;&lt;p&gt;The &lt;code&gt;UITableViewDataSource&lt;/code&gt; protocol changes significantly and the implementations of the various methods can seem daunting at first. Most of the complexity, however, is due to nested &lt;code&gt;if&lt;/code&gt; statements.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 2;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (section == 0) {
        return [self.locations count] + 1;
    }
    return 2;
}
&lt;/pre&gt;&lt;p&gt;We also implement &lt;code&gt;tableView:titleForHeaderInSection:&lt;/code&gt; and &lt;code&gt;tableView:viewForHeaderInSection:&lt;/code&gt; to replace the default section headers with a custom design that matches the application&amp;#8217;s design. When implementing &lt;code&gt;tableView:viewForHeaderInSection:&lt;/code&gt;, it is important to also implement &lt;code&gt;tableView:heightForHeaderInSection:&lt;/code&gt;.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    switch (section) {
        case 0: {
            return NSLocalizedString(@&amp;quot;Locations&amp;quot;, nil);
            break;
        }
        default: {
            return NSLocalizedString(@&amp;quot;Temperature&amp;quot;, nil);
            break;
        }
    }
    return nil;
}
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    // Header Text
    NSString *text = [self tableView:tableView titleForHeaderInSection:section];
    // Helpers
    CGRect labelFrame = CGRectMake(12.0, 0.0, tableView.bounds.size.width, 44.0);
    // Initialize Label
    UILabel *label = [[UILabel alloc] initWithFrame:labelFrame];
    // Configure Label
    [label setText:text];
    [label setTextColor:kMTColorOrange];
    [label setFont:[UIFont fontWithName:@&amp;quot;GillSans&amp;quot; size:20.0]];
    [label setBackgroundColor:[UIColor clearColor]];
    // Initialize View
    UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, tableView.bounds.size.width, 34.0)];
    [backgroundView setBackgroundColor:[UIColor clearColor]];
    [backgroundView addSubview:label];
    return backgroundView;
}
- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
    return 40.0;
}
&lt;/pre&gt;&lt;p&gt;We make use of &lt;code&gt;tableView:heightForFooterInSection:&lt;/code&gt; to create some whitespace between the top and bottom sections. This means that we also need to implement &lt;code&gt;tableView:viewForFooterInSection:&lt;/code&gt;.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (UIView *)tableView:(UITableView *)tableView viewForFooterInSection:(NSInteger)section {
    // Initialize View
    UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, tableView.bounds.size.width, 34.0)];
    [backgroundView setBackgroundColor:[UIColor whiteColor]];
    return backgroundView;
}
- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
    if (section == 0) {
        return 40.0;
    }
    return 0.0;
}
&lt;/pre&gt;&lt;p&gt;The implementation of &lt;code&gt;tableView:cellForRowAtIndexPath:&lt;/code&gt; is a bit more complex due to the three cell types in the table view.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = nil;
    if (indexPath.section == 0) {
        if (indexPath.row == 0) {
            cell = [tableView dequeueReusableCellWithIdentifier:AddLocationCell forIndexPath:indexPath];
        } else {
            cell = [tableView dequeueReusableCellWithIdentifier:LocationCell forIndexPath:indexPath];
        }
    } else {
        cell = [tableView dequeueReusableCellWithIdentifier:SettingsCell forIndexPath:indexPath];
    }
    // Configure Cell
    [self configureCell:cell atIndexPath:indexPath];
    return cell;
}
&lt;/pre&gt;&lt;p&gt;In &lt;code&gt;configureCell:atIndexPath:&lt;/code&gt;, we configure each cell. As I wrote earlier, the complexity is primarily due to nested &lt;code&gt;if&lt;/code&gt; statements. Tapping the delete button in a location cell sends a message of &lt;code&gt;deleteLocation:&lt;/code&gt; to the locations view controller. We will implement &lt;code&gt;deleteLocation:&lt;/code&gt; shortly.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath {
    // Helpers
    UIFont *fontLight = [UIFont fontWithName:@&amp;quot;GillSans-Light&amp;quot; size:18.0];
    UIFont *fontRegular = [UIFont fontWithName:@&amp;quot;GillSans&amp;quot; size:18.0];
    // Background View Image
    UIImage *backgroundImage = [[UIImage imageNamed:@&amp;quot;background-location-cell&amp;quot;] resizableImageWithCapInsets:UIEdgeInsetsMake(10.0, 0.0, 0.0, 10.0)];
    // Configure Table View Cell
    [cell.textLabel setFont:fontLight];
    [cell.textLabel setTextColor:kMTColorGray];
    [cell.textLabel setBackgroundColor:[UIColor clearColor]];
    [cell setSelectionStyle:UITableViewCellSelectionStyleNone];
    if (indexPath.section == 0) {
        if (indexPath.row == 0) {
            [cell.textLabel setText:@&amp;quot;Add Current Location&amp;quot;];
            [cell.imageView setContentMode:UIViewContentModeCenter];
            [cell.imageView setImage:[UIImage imageNamed:@&amp;quot;icon-add-location&amp;quot;]];
            // Background View Image
            backgroundImage = [[UIImage imageNamed:@&amp;quot;background-add-location-cell&amp;quot;] resizableImageWithCapInsets:UIEdgeInsetsMake(10.0, 0.0, 0.0, 10.0)];
        } else {
            // Fetch Location
            NSDictionary *location = [self.locations objectAtIndex:(indexPath.row - 1)];
            // Configure Cell
            [[(MTLocationCell *)cell buttonDelete] addTarget:self action:@selector(deleteLocation:) forControlEvents:UIControlEventTouchUpInside];
            [[(MTLocationCell *)cell labelLocation] setText:[NSString stringWithFormat:@&amp;quot;%@, %@&amp;quot;, location[MTLocationKeyCity], location[MTLocationKeyCountry]]];
        }
    } else {
        if (indexPath.row == 0) {
            [cell.textLabel setText:NSLocalizedString(@&amp;quot;Fahrenheit&amp;quot;, nil)];
            if ([NSUserDefaults isDefaultCelcius]) {
                [cell.textLabel setFont:fontLight];
                [cell.textLabel setTextColor:kMTColorGray];
            } else {
                [cell.textLabel setFont:fontRegular];
                [cell.textLabel setTextColor:kMTColorGreen];
            }
        } else {
            [cell.textLabel setText:NSLocalizedString(@&amp;quot;Celsius&amp;quot;, nil)];
            if ([NSUserDefaults isDefaultCelcius]) {
                [cell.textLabel setFont:fontRegular];
                [cell.textLabel setTextColor:kMTColorGreen];
            } else {
                [cell.textLabel setFont:fontLight];
                [cell.textLabel setTextColor:kMTColorGray];
            }
        }
    }
    if (backgroundImage) {
        // Background View
        UIImageView *backgroundView = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, cell.frame.size.width, cell.frame.size.height)];
        [backgroundView setAutoresizingMask:(UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight)];
        [backgroundView setImage:backgroundImage];
        [cell setBackgroundView:backgroundView];
    }
}
&lt;/pre&gt;&lt;p&gt;Because locations can now be deleted by tapping the delete button in the location cells, the rows themselves no longer need to be editable. This means that the implementation of &lt;code&gt;tableView:canEditRowAtIndexPath:&lt;/code&gt; can be reduced to returning &lt;code&gt;NO&lt;/code&gt; and the implementation of &lt;code&gt;tableView:commitEditingStyle:forRowAtIndexPath:&lt;/code&gt; can be removed altogether.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    return NO;
}
&lt;/pre&gt;&lt;h3&gt;Step 4: Updating the Table View Delegate Protocol&lt;/h3&gt;&lt;p&gt;In &lt;code&gt;tableView:didSelectRowAtIndexPath:&lt;/code&gt;, we add a bit more complexity due to the inclusion of the second section containing the temperature setting. Thanks to our category on &lt;code&gt;NSUserDefaults&lt;/code&gt;, the implementation is simple and concise.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    [tableView deselectRowAtIndexPath:indexPath animated:YES];
    if (indexPath.section == 0) {
        if (indexPath.row == 0) {
            // Notify Delegate
            [self.delegate controllerShouldAddCurrentLocation:self];
        } else {
            // Fetch Location
            NSDictionary *location = [self.locations objectAtIndex:(indexPath.row - 1)];
            // Notify Delegate
            [self.delegate controller:self didSelectLocation:location];
        }
    } else {
        if (indexPath.row == 0 &amp;amp;&amp;amp; [NSUserDefaults isDefaultCelcius]) {
            [NSUserDefaults setDefaultToFahrenheit];
        } else if (![NSUserDefaults isDefaultCelcius]) {
            [NSUserDefaults setDefaultToCelcius];
        }
        // Update Section
        [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationNone];
    }
    // Show Center View Controller
    [self.viewDeckController closeLeftViewAnimated:YES];
}
&lt;/pre&gt;&lt;p&gt;The rows in Chris&amp;#8217;s design are slightly taller than the default height of 44 points. To put this detail into practice, we implement &lt;code&gt;tableView:heightForRowAtIndexPath:&lt;/code&gt; as shown below.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
    return 50.0;
}
&lt;/pre&gt;&lt;h3&gt;Step 5: Deleting Locations (Revisited)&lt;/h3&gt;&lt;p&gt;The last thing that we need to do is implement the &lt;code&gt;deleteLocation:&lt;/code&gt; method that is invoked when the delete button is tapped in a location cell. The implementation is more verbose than you might expect. Inferring the row number from the cell to which the delete button belongs isn&amp;#8217;t as trivial as it should be. However, once we have the index path of the cell to which the button belongs, we only need to update the array of locations, update the user defaults database, and update the table view.&lt;/p&gt;&lt;pre class="brush: objc; title: ;"&gt;
- (void)deleteLocation:(id)sender {
    UITableViewCell *cell = (UITableViewCell *)[[(UIButton *)sender superview] superview];
    NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
    // Update Locations
    [self.locations removeObjectAtIndex:(indexPath.row - 1)];
    // Update User Defaults
    [[NSUserDefaults standardUserDefaults] setObject:self.locations forKey:MTRainUserDefaultsLocations];
    // Update Table View
    [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationTop];
}
&lt;/pre&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;5.&lt;/span&gt; Finishing Touch&lt;/h2&gt;&lt;p&gt;To finish our project, we need to replace the default launch images with the ones provided by Chris Carey. The launch images are also included in the source files of this article.&lt;/p&gt;&lt;p&gt;Build and run the application to see the final result in action. Even though we have spent quite some time creating and designing the application, there are still some rough edges. It would also be nice to implement a caching mechanism so that we can show cached data to the user as long as a request to the Forecast API hasn&amp;#8217;t returned. These are a few examples of refinements that we can add to our application.&lt;/p&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;p&gt;Creating the user interface was quite a bit of work, but the code involved wasn&amp;#8217;t all that complicated. I hope this tutorial has shown you what a great design can do for an application. Consumer applications in particular really benefit from an appealing, fresh design like the one we used in this tutorial.&lt;/p&gt;&lt;img src="http://feeds.feedburner.com/~r/MobileTuts/~4/GLazVui9oEo" height="1" width="1"/&gt;</description> <wfw:commentRss>http://mobile.tutsplus.com/tutorials/iphone/create-a-weather-app-with-forecast-user-interface/feed/</wfw:commentRss> <slash:comments>12</slash:comments> <feedburner:origLink>http://mobile.tutsplus.com/tutorials/iphone/create-a-weather-app-with-forecast-user-interface/</feedburner:origLink></item> <item><title>Build a Monster Smashing Game with Cocos2D: Project Setup</title><link>http://feedproxy.google.com/~r/MobileTuts/~3/Qicpc29U9JQ/</link> <comments>http://mobile.tutsplus.com/tutorials/iphone/build-a-monster-smashing-game-with-cocos2d-project-setup/#comments</comments> <pubDate>Thu, 30 May 2013 20:43:18 +0000</pubDate> <dc:creator>Jorge Costa and Orlando Pereira</dc:creator> <category><![CDATA[Game Engines]]></category> <category><![CDATA[iOS SDK]]></category> <guid isPermaLink="false">http://mobile.tutsplus.com/?p=17352</guid> <description>&lt;p&gt;This tutorial will teach you how to use the Cocos2D iOS framework in order to create simple yet advanced 2D games aimed at all iOS devices. It&amp;#8217;s designed for both novice and advanced users. Along the way, you&amp;#8217;ll learn about the Cocos2D core concepts, touch interaction, menus and transitions, actions, particles, and collisions. Read on!&lt;br
/&gt;&lt;/p&gt;&lt;p&gt;The Cocos2D tutorial will be divided into three parts in order to completely cover each section. After the three part tutorial, you&amp;#8217;ll be able to create an interesting 2D game using Cocos2D!&lt;/p&gt;&lt;p&gt;Each part will produce a practical result, and the sum of all parts will produce the final game. Despite the fact that each part can be read independently, for better understanding and guidance we suggest that the tutorial be followed step by step. We&amp;#8217;ve also included the source code for each part separately, providing a way to start the tutorial at any point of the tutorial without having to read the prior portions.&lt;/p&gt;&lt;hr
/&gt; Organization of the Series:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a
href="http://mobile.tutsplus.com/?p=17352"&gt;Project Structure &amp;#038; Setup&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a
href="http://mobile.tutsplus.com/?p=17365"&gt;Movement &amp;#038; Animations&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a
href="http://mobile.tutsplus.com/?p=17408"&gt;Sound &amp;#038; Game Mechanics&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Before we start the tutorial, we&amp;#8217;d like to thank &lt;a
href="http://www.behance.net/Bellones"&gt;Rodrigo Bellão&lt;/a&gt; for providing us with the images of the monsters.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;1.&lt;/span&gt; Installation and Basics&lt;/h2&gt;&lt;p&gt;If this is your first time working with Cocos2D, you&amp;#8217;ll need to download and install the SDK from the &lt;a
href="http://www.cocos2d-iphone.org/download"&gt;Cocos2D for iPhone Webpage&lt;/a&gt; or from the &lt;a
href="https://github.com/cocos2d/cocos2d-iphone"&gt;GitHub Repository&lt;/a&gt;. Once you&amp;#8217;ve downloaded it, you&amp;#8217;ll need to install the Xcode project templates. Unzip the package and open up a terminal window on the directory you downloaded Cocos2D to.&lt;/p&gt;&lt;p&gt;Enter the following command.&lt;/p&gt;&lt;p&gt;&lt;code&gt;&lt;br
/&gt; ./install-templates.sh -f -u&lt;br
/&gt; &lt;/code&gt;&lt;/p&gt;&lt;p&gt;This command will only work if Xcode is installed within the default directory.&lt;/p&gt;&lt;hr/&gt;&lt;h2&gt;&lt;span&gt;2.&lt;/span&gt; Monster Smashing!&lt;/h2&gt;&lt;p&gt;Now we have Cocos2D installed. To start our game, we need to launch Xcode and go to &lt;strong&gt;File Menu &gt; New &gt; Project&lt;/strong&gt;. We&amp;#8217;ll see something like the following image.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Cocos2D-Tutorial_Part-One_1.png" alt="Figure 1: Choosing Cocos2D template" /&gt;&lt;/p&gt; &lt;figcaption&gt;Illustration of the template chooser (Xcode).&lt;/figcaption&gt; &lt;/figure&gt;&lt;p&gt;We need to choose the &amp;#8220;&lt;strong&gt;Cocos2D iOS&lt;/strong&gt;&amp;#8221; template (from the Cocos2D v2.x lateral list). This template creates what we need to start our project, and includes the libraries required to run Cocos2D.  The project is created with three classes (&lt;strong&gt;AppDelegate, HelloWorldLayer, and IntroLayer&lt;/strong&gt;). Today, you will be working with &lt;strong&gt;HelloWorldLayer&lt;/strong&gt;.&lt;/p&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;3.&lt;/span&gt; Pixel and Point Notation&lt;/h2&gt;&lt;p&gt;A pixel is the smallest controllable element of a picture represented on the screen. There are several display resolutions in the iDevice family. Thus, the Cocos2D framework introduces a notation to help developers positioning objects in the screen. This is called point notation.&lt;/p&gt;&lt;p&gt;The device coordinate space is normally measured in pixels. However, the logical coordinate space is measured in points. The next table presents the direct relation between devices, points, and pixels.&lt;/p&gt;&lt;table
border="1"&gt;&lt;tr&gt;&lt;td&gt;Device&lt;/td&gt;&lt;td&gt;Points&lt;/td&gt;&lt;td&gt;Pixel&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;iPhone 3G&lt;/td&gt;&lt;td&gt;480&amp;#215;320&lt;/td&gt;&lt;td&gt;480&amp;#215;320&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;iPhone Retina&lt;/td&gt;&lt;td&gt;480&amp;#215;320&lt;/td&gt;&lt;td&gt;960&amp;#215;640&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;iPad 3&lt;/td&gt;&lt;td&gt;1024&amp;#215;768&lt;/td&gt;&lt;td&gt;2048&amp;#215;1536&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&lt;p&gt;From Cocos2D version 0.99.5-rc0 and above, the user can place objects in the screen using only point notation. This will offer a great advantage since the user knows that the object placement will be the same despite the end device where the application will run.&lt;/p&gt;&lt;p&gt;Nevertheless, if the user wants to, it&amp;#8217;s possible to place objects using pixel notation simply by modifying the type of message that we pass to the object.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
// Director
CCDirector *director [CCDirector sharedDirector];
CGSize objectA = [director winSize]; // points notation
CGSize objectB = [director winSizeInPixels]; // pixel notation
// Node
CCNode *node = [...];
CGPoint posA = [node position];  // points notation
CGPoint posB = [node positionInPixels]; // pixel notation
// Sprite
CCSprite *sprite = [...];
CGRect rectA = [sprite rect]; // points notation
CGRect rectB = [sprite rectInPixels]; // pixel notation
&lt;/pre&gt;&lt;p&gt;Note that the object setters can also be used in both notations.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
[sprite setPosition:ccp(x,y)]; // points notation
[sprite setPositionInPixels:(x,y)] // pixel notation
&lt;/pre&gt;&lt;p&gt;We recommend using the point notation since we know that the positions will be the same in all devices.&lt;/p&gt;&lt;p&gt;Now that we know how the pixel and point notation work, the next step is to understand where the objects are positioned when we pass a specific coordinate. In Codos2D, the point (0,0) is in the bottom left corner of the screen. Thus, the top-right corner has the (480,320) point.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Cocos2D-Tutorial_Part-One_2.png" alt="Figure 2: x-,y- axis coordination system" /&gt;&lt;/p&gt; &lt;figcaption&gt;Illustration of pixel and dot notation using the iPhone simulator.&lt;/figcaption&gt; &lt;/figure&gt;&lt;p&gt;For example, to position a sprite you had to do:&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
sprite.position = ccp(480,320); // at the top-right corner
sprite.position = ccp(0,320); // at the top-left corner
sprite.position = ccp(480,0); // at the bottom-right corner
sprite.position = ccp(240,160); // at the center of the screen
&lt;/pre&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;4.&lt;/span&gt; Background and Logo&lt;/h2&gt;&lt;p&gt;Cocos2D introduced the concept of scenes. Each scene can be seen as a different screen, which is used to incorporate menus, levels, credits, and everything else that you see during the game. Note that only one scene can be active at a given time.&lt;/p&gt;&lt;p&gt;Inside the scenes, you can have several layers (like Photoshop). The layers can have several properties, and we can have a large number of them on the screen simultaneously. They can have several properties such as background color, animation, a menu, or even a shadow.&lt;/p&gt;&lt;p&gt;Sprites are simply 2D images that can be moved, rotated, scaled, animated, and so on. In the next step, you will change the project source code and add a sprite.&lt;/p&gt;&lt;p&gt;Before you add a sprite, some artwork, which is available in the resources folder, is required.&lt;/p&gt;&lt;p&gt;All resources used in this tutorial are designed for the original iPad resolution.&lt;/p&gt;&lt;p&gt;Once you have downloaded the resources, you will find six images. Copy them to the resources folder of your project and make sure that the option &amp;#8220;&lt;strong&gt;Copy items into destination goups&amp;#8217;s folder (if needed)&lt;/strong&gt;&amp;#8221; is checked.&lt;/p&gt;&lt;p&gt;Now, in the &lt;strong&gt;HelloWorldLayer.m&lt;/strong&gt; you can delete everything inside the condition &lt;code&gt;if( (self=[super init]))&lt;/code&gt;. The sprite creation can be achieved in code using the following snippet.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
CGSize winSize = [CCDirector sharedDirector].winSize;
CCSprite *backgroundImage = [CCSprite spriteWithFile:@&amp;quot;WoodRetroApple_iPad_HomeScreen.jpg&amp;quot;];
backgroundImage.position = ccp(winSize.width/2, winSize.height/2);
[self addChild:backgroundImage z:-2];
&lt;/pre&gt;&lt;p&gt;With the above-mentioned snippet you can change the default background image of that class. The code is simple to understand, and to summarize.&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Ask for the window size&lt;/li&gt;&lt;li&gt;Initialize a CCSprite with the picture we want to load&lt;/li&gt;&lt;li&gt;Center the sprite on screen&lt;/li&gt;&lt;li&gt;Add the CCSprite to the scene&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Note that we put the &lt;code&gt;z = -2&lt;/code&gt; because the background needs to stay behind all objects.&lt;/p&gt;&lt;p&gt;Let&amp;#8217;s add a logo. Looking at the above-mentioned code, we already know how to achieve it. The process is simple and straightforward. If you need some help, you can use the following code.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
CCSprite *logo = [CCSprite spriteWithFile:@&amp;quot;MonsterSmashing.png&amp;quot;];
logo.scale = 1.2;
logo.position =  ccp(winSize.width /2 , 800 );
[self addChild: logo];
&lt;/pre&gt;&lt;p&gt;It&amp;#8217;s now time to run the project and see if everything is working as expected. You should see similar to the next screen.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Cocos2D-Tutorial_Part-One_3.png" alt="Figure 3: Monster Smashing Logo and Background" /&gt;&lt;/p&gt; &lt;figcaption&gt;Illustration of the first screen. The screen contains the default game name and logo.&lt;/figcaption&gt; &lt;/figure&gt;&lt;hr/&gt;&lt;h2&gt;&lt;span&gt;5.&lt;/span&gt; Creating the Menu&lt;/h2&gt;&lt;p&gt;The main objective for this step is to add a default menu. The menu will have two options:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Play&lt;/li&gt;&lt;li&gt;Sound&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The Play option will start a new game, while the Sound option is a toggle button that will provide us a way to stop or start the sound engine (in this case the background music).&lt;/p&gt;&lt;p&gt;To implement the Play button (using the &lt;code&gt;CCMenuItem&lt;/code&gt; class), we just need to add a line (for now). This line represents an Item of the Menu. The option is represented using an image (added previously to the resources)&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
CCMenuItem *startGameButtonImage = [CCMenuItemImage itemFromNormalImage:@&amp;quot;playButton.png&amp;quot; selectedImage:@&amp;quot;playButtonSelected.png&amp;quot; target:self selector:@selector(onStartGamePressed)];
&lt;/pre&gt;&lt;p&gt;To create and describe the Play Button we need to pass it through several messages. The &lt;code&gt;itemFromNormalImage&lt;/code&gt; is the image location information, and the &lt;code&gt;selectedImage&lt;/code&gt; is the image that appears when our finger is hovering over the item. The &lt;code&gt;selector&lt;/code&gt; is the method that will be called when the user lifts their finger from the menu item, which in this case is the method &lt;code&gt;onStartgamePressed&lt;/code&gt;. We&amp;#8217;ll talk about that later.&lt;/p&gt;&lt;p&gt;The toggle button is more complex than the play button since it uses two states, on and off. We need to define the two states and then add them to the final toggle button, &lt;code&gt;CCMenuItemToogle&lt;/code&gt;. The &lt;code&gt;on&lt;/code&gt; and &lt;code&gt;off&lt;/code&gt; button is defined as the play button.&lt;/p&gt;&lt;p&gt;After we create the two options, we need to join the options. Use the snippet below for this.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
CCMenuItem *startGameButtonImage = [CCMenuItemImage itemFromNormalImage:@&amp;quot;playButton.png&amp;quot; selectedImage:@&amp;quot;playButtonSelected.png&amp;quot; target:self selector:@selector(onStartGamePressed)];
CCMenuItem *_soundOn = [[CCMenuItemImage  itemFromNormalImage:@&amp;quot;soundOn.png&amp;quot;
                                                         selectedImage:@&amp;quot;soundOnSelected.png&amp;quot; target:nil selector:nil] retain];
CCMenuItem *_soundOff = [[CCMenuItemImage itemFromNormalImage:@&amp;quot;soundOff.png&amp;quot;
                                                         selectedImage:@&amp;quot;soundOffSelected.png&amp;quot; target:nil selector:nil] retain];
CCMenuItemToggle *toggleItem = [CCMenuItemToggle itemWithTarget:self
                                                               selector:@selector(soundButtonTapped:) items:_soundOn, _soundOff, nil];
&lt;/pre&gt;&lt;p&gt;After adding the above snippet, we need to create the real menu with the inherent options. We need to use a &lt;code&gt;CCMenu&lt;/code&gt; and send several &lt;code&gt;CCMenuItems&lt;/code&gt; through the method &lt;code&gt;menuWithItems&lt;/code&gt;. As with any other object, we must define its position and its padding, which in this case is vertical. Here&amp;#8217;s the code.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
CCMenu *menu = [CCMenu menuWithItems:startGameButtonImage, toggleItem, nil];
menu.position = ccp(winSize.width * 0.5f, winSize.height * 0.4f);
[menu alignItemsVerticallyWithPadding:15];
//Add the menu as a child to this layer
[self addChild:menu];
&lt;/pre&gt;&lt;p&gt;Previously, we said that the selector parameter called a method. We call two methods, &lt;code&gt;onStartGamePressed&lt;/code&gt; and &lt;code&gt;soundButtonTapped&lt;/code&gt;. The first one will replace the current scene, while the second will activate or deactivate the game sound.&lt;/p&gt;&lt;p&gt;Before we go to the method implementations, we need to create a new scene. So, go to &lt;strong&gt;File &gt; New &gt; File&amp;#8230;&lt;/strong&gt; and select a &lt;strong&gt;CCNode&lt;/strong&gt; class and name it &amp;#8220;&lt;strong&gt;MonsterRun&lt;/strong&gt;&amp;#8220;. Two new files will be added to your project, &lt;strong&gt;MonsterRun.h and MonsterRun.m&lt;/strong&gt;). Make sure that the class uses the following code.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
+(CCScene *) scene {
  CCScene *scene = [CCScene node];
  MonsterRun *layer = [MonsterRun node];
  [scene addChild: layer];
  return scene;
}
&lt;/pre&gt;&lt;p&gt;Now, we can go back to the &lt;code&gt;HelloWorldLayer.m&lt;/code&gt; and reference the MonsterRun. We use the following line to create it.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
#import &amp;quot;MonsterRun.h&amp;quot;
&lt;/pre&gt;&lt;p&gt;For now, we&amp;#8217;ll leave this class and its code alone. It&amp;#8217;ll be covered in the next tutorial. Let&amp;#8217;s rewind a bit for the menus and the two methods that we talked about before, &lt;code&gt;onStartGamePressed&lt;/code&gt; and &lt;code&gt;soundButtonTapped&lt;/code&gt;.&lt;/p&gt;&lt;pre class="brush: jscript; title: ;"&gt;
- (void)soundButtonTapped:(id)sender {
    // Covered in Part 3
}
- (void)onStartGamePressed {
  CCScene *MonsterRunScene = [MonsterRun scene];
  CCTransitionFlipAngular *transition = [CCTransitionFlipAngular transitionWithDuration:0.5f scene:helloWorldScene];
  [[CCDirector sharedDirector] replaceScene:MonsterRunScene];
}
&lt;/pre&gt;&lt;p&gt;Now run the project in order to see if everything is working correctly. You will see something similar to the next image.&lt;/p&gt; &lt;figure
class="tutorial_image"&gt; &lt;img
src="http://cdn.tutsplus.com/mobile.tutsplus.com/uploads/2013/05/Cocos2D-Tutorial_Part-One_4.png" alt="Figure 4: Monster Smashing Logo and Background" /&gt;&lt;/p&gt; &lt;figcaption&gt;Illustration of the first screen. The screen contains the default game name, logo, and options menu.&lt;/figcaption&gt; &lt;/figure&gt;&lt;hr
/&gt;&lt;h2&gt;&lt;span&gt;6.&lt;/span&gt; Results&lt;/h2&gt;&lt;p&gt;At this point, you have to be able to understand and perform the following tasks:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Install the Cocos2D framework.&lt;/li&gt;&lt;li&gt;Configure a Cocos2D project.&lt;/li&gt;&lt;li&gt;Implement scenes, layers, sprites and use the director.&lt;/li&gt;&lt;li&gt;Pixel and point differences.&lt;/li&gt;&lt;li&gt;Screen positioning and x-, y- axis orientation.&lt;/li&gt;&lt;li&gt;Define and use menus.&lt;/li&gt;&lt;/ul&gt;&lt;img src="http://feeds.feedburner.com/~r/MobileTuts/~4/Qicpc29U9JQ" height="1" width="1"/&gt;</description> <wfw:commentRss>http://mobile.tutsplus.com/tutorials/iphone/build-a-monster-smashing-game-with-cocos2d-project-setup/feed/</wfw:commentRss> <slash:comments>15</slash:comments> <feedburner:origLink>http://mobile.tutsplus.com/tutorials/iphone/build-a-monster-smashing-game-with-cocos2d-project-setup/</feedburner:origLink></item> </channel> </rss><!-- Dynamic Page Served (once) in 1.226 seconds -->
