Monday, October 3, 2011

Icons on iOS and OS X

Sometime I need some small table to resume quickly the artwork required for the iOS and OsX applications. They are often the same image, but in different resolutions. Here they are:

OsX



ResolutionNotes
Icons1024 x 1024 pixels
512 x 512 pixels
256 x 256 pixels
128 x 128 pixels
32 x 32 pixels
16 x 16 pixels

Toolbar icons
(inside control)
19 x 19 pixelsOutline style, recommanded to be black
Toolbar icon buttons32 x 32 pixelsColor with antialiasing
Sidebar icons16 x 16 pixels
18 x 18 pixels
32 x 32 pixels
Black and white with alpha, all three resolutions required
More information for Os X here: Icon Design Guidelines

iOS


ResolutionNotes
Icon for iPhone57 x 57 pixelsSuggested name: Icon.png. No shadow or round corners required.
Icon for iPhone
with Retina Display
114 x 114 pixelsSuggested name: Icon@2x.png. No shadow or round corners required.
Icon for iPad72 x 72 pixelsSuggested name: Icon-72.png. No shadow or round corners required.
Small icons iPhone
(Spotlight and settings)
29 x 29 pixels
Small icons iPhone
High Resolution
(Spotlight and settings)
58 x 58 pixels
Small icons iPad
(Spotlight)
50 x 50 pixelsIt trims the side pixels (safe area 48x48)
Small icons iPhone
(settings)
29 x 29 pixels
Toolbar icons for iPhone20 x 20 pixelsApproximately
Toolbar icons for iPhone
High Resolution
40 x 40 pixelsApproximately
Toolbar icons iPad20 x 20 pixelsApproximately
Tab bar icons iPhone30 x 30 pixelsApproximately
Tab bar icons iPhone
High resolution
60 x 60 pixelsApproximately
Tab bar icons iPad30 x 30 pixelsApproximately
More information for iOS here: Custom Icon and Image Creation Guidelines

Open source/free toolbar icon sets

Some link to free/open source iPhone toolbar icon set:

Tuesday, September 27, 2011

How to take a screenshot with the Android SDK

You can take a screenshot in Android using one of the several Market's application, or using "ddms", a tool you can find in the tools directory of the sdk.

So, go to that directory and start it:

cd [sdkdir]/tools
./ddms


Then go on the Device menu ant click on Screen capture. Then save the image file.






If you want to take a screenshot from Eclipse, it is even simpler.
Just set the DDMS perspective:
Look for the camera button, and click on it to show the following menu:




Here you can find the "Screen Capture" command.

Monday, September 19, 2011

How to check if our app is running on an iPad or iPhon

The easiest way is using the UI_USER_INTERFACE_IDIOM macro. Only SDKs 3.2 an later support it. Here an example:

if (UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPad) 
{
  NSLog(@"I'm on iPad");
}

In the same way:

if (UI_USER_INTERFACE_IDIOM()==UIUserInterfaceIdiomPhone) {
  NSLog(@"I'm on iPhone or on an iPod touch"); 
}

The macro uses the [[UIDevice currentDevice] userInterfaceIdiom] method. If you are sure that your SDK supports the userInterfaceIdiom selector, you can also use something like this:

[[UIDevice currentDevice] userInterfaceIdiom]==UIUserInterfaceIdiomPad

Thursday, September 8, 2011

Android's services

Android uses services to perform long running jobs, or background tasks (think to a network interaction or an mp3 player). How can we start a service?

We should begin extending the android.app.Service class:


public class TestService extends Service {

     @Override

     public IBinder onBind(Intent arg0) {

          return null;

     }



     public void onCreate () {

       Log.i("onCreate", "onCreate");   

     }

    
     @Override
     public int onStartCommand(Intent intent, int flags, int startId) {

           Log.i("onStartCommand", "onStartCommand");  

           Toast.makeText(this, "Hi, this is a service!",
                           Toast.LENGTH_LONG).show();

           return START_STICKY;

      }

}

The two most important methods, for the purposes of this post, are onCreate and onStartCommand. Android invokes the first, when the service is created, and the second one, when it is executed. The Toast.makeText(…) command is a nice way to give notifications to the users.

Please note that the onStartCommand callback exists only in the versions 2.0 and later. In older versions you should override the onStart method (now deprecated).

Once you have you service’s skeleton, you can register with the operating system, adding a line to the manifest:

 <service android:name="TestService" android:enabled="true" >service>


Or in a easier way, using the Eclipse interface:

At the end is time to start our service, using two instructions:

Intent intent = new Intent(this, TestService.class);

     startService(intent);

We create an android.content.Intent instance, and then we use it in the startService method. The Intent, ask you for a context (your calling Activity is fine), and the implementation class. He will take care of the instantiation. The startService will call your onStartCommand procedure, passing it also the intent instance. A nice place to do it could be in the onClick method:


     public void onClick(View v) {

          switch (v.getId()) {

          case R.id.buttonStart:

               Intent intent = new Intent(this, TestService.class);

               startService(intent);

               break;

          }

     }

Friday, September 2, 2011

How to take screenshots directly on the iPhones

If you want to take a screen-shot directly from your iPhone/iPod touch/iPad, and find it directly in your photo library, there is a simple procedure:
  1. Press the Home button, without releasing it;
  2. Press and release the Sleep button;
  3. Release the Home button.
That's all! Now go in your camera roll, and enjoy the image of screen. Some more thing on screen-shots here!
The (so called) Home and Sleep buttons are marked in red in the picture.

Wednesday, April 20, 2011

Load an XML file in Mac Os X using Cocoa: NSXMLDocument

Here another snippet on how to load an XML file using the NSXMLDocument class. Our goal is to show an “Open File” dialog box (as said in the last post), chose an xml file, and put it in a data structure (NSXMLDocument)

Here’s the code:

-(BOOL) LoadXml : (NSError **)err
{
    NSURL *fileUrl = nil;
    
    NSOpenPanel* openDlg = [NSOpenPanel openPanel];
    [openDlg setCanChooseFiles:YES];
    [openDlg setCanChooseDirectories:NO];
    [openDlg setAllowsMultipleSelection: NO];
    [openDlg setAllowedFileTypes:[NSArray arrayWithObjects:@"xml", 
             nil]];
    if ( [openDlg runModal] == NSOKButton )
    {
        fileUrl = [openDlg URL];
    }
    if (fileUrl==nil)
    {
        return NO;
    }
    
    xmlDoc = [[NSXMLDocument alloc] initWithContentsOfURL:fileUrl 
       options:(NSXMLNodePreserveWhitespace|NSXMLNodePreserveCDATA)
       error:err];
    if (xmlDoc == nil) {
        xmlDoc = [[NSXMLDocument alloc] initWithContentsOfURL:fileUrl
           options:NSXMLDocumentTidyXML error:&err];
    }
    if (xmlDoc == nil) 
  return NO;
    
    ...
}

The only “strange” thing suggested by the Apple’s example and reported here, is the double initialization of NSXMLDocument, with different parameters: the first one with NSXMLNodePreserveWhitespace|NSXMLNodePreserveCDATA, the second one with NSXMLDocumentTidyXML.

We are trying to recover from parsing errors. NSXMLDocumentTidyXML reformats the document before the parsing. Hopefully it can correct some error, but it modifies the original file (take a look at the documentation).

More information is in the “Introduction to Tree-Based XML Programming Guide for Cocoa” on the Apple Devveloper web site.

Tuesday, April 12, 2011

Open a file from the Mac OSX GUI: NSOpenPanel

This is a quick snippet that presents how to show a dialog to choose a file in Mac OS X programming in Objective-C. We will use the NSOpenPanel class.

Our first step is to write an IBAction routine, to answer to the user input, and link it to the interface (using XCode).
-(IBAction) action_OpenFile: (id) sender
{
}
Then we can populate it instantiating the NSOpenPanel class:

NSOpenPanel* openPanel = [NSOpenPanel openPanel];

This instantiate the class using the autorelease feature, so you don’t have to release it. Now you can personalize it using the features you need. For example the lines allow the user to choose just one file and not the directories:
[openPanel setCanChooseFiles:YES];
[openPanel setCanChooseDirectories:NO];
[openPanel setAllowsMultipleSelection: NO];

But what about the file types?
You may want to allocate an array of NSString with the list of allowed file types, and assign it to the panel. The following lines limit the users to choose the text files (txt or doc):

NSArray *tarr = [NSArray arrayWithObjects:@"txt", @"doc", nil];
[openPanel setAllowedFileTypes:tarr ];

Now you can show the panel, check if the user pressed the OK button, and retrieve the url of the selected file:
if ( [openPanel runModal] == NSOKButton ){
fileUrl = [openPanel URL];
}

Other methods runModal* exist to show the panel, but most of them are declared deprecated in the last OSX versions.

Here the final code:

-(IBAction) action_OpenFile: (id) sender
{
NSOpenPanel* openPanel = [NSOpenPanel openPanel];
[openPanel setCanChooseFiles:YES];
[openPanel setCanChooseDirectories:NO];
[openPanel setAllowsMultipleSelection: NO];
NSArray *tarr = [NSArray arrayWithObjects:@"txt", @"doc", nil];
[openPanel setAllowedFileTypes:tarr ];
if ( [openPanel runModal] == NSOKButton )
{
fileUrl = [openPanel URL];
// ...
// Use the file
// ...
}
}

Emilio

Thursday, April 7, 2011

iPhone screenshots for the App Store


Apple suggests formatting the screenshots for iPhone and iPad with a specific resolution, and, possibly, without the status bar. If you use XCode to take the screenshots you can find that they are not exactly that way, and they are stored in png format.
Updating the screenshots could be a boring task, so why don’t you write a script taking advantage of ImageMagick that automatically crop your images and convert them in jpg? In that way they will be ready to be posted on the App Store and on your web site.

We want to do the following steps:
  1. Crop the images to a specific width and height
  2. Convert them in jpg to reduce their weight
  3. Prepare some thumbnail for our web site

ImageMagick has several tools, we will just use mogrify. Our first goal is to cut the status bar. If you took the screenshot from an iPhone with the Retina Display, the bar will be 40 pixels tall. On the iPad will be 20 pixels tall. For example here there is a screenshot taken from our Sudoku:

The operation we want to apply is the “crop”. The original image’s size is 640x960 pixels on portrait Retina Displays (768x1024 on iPads). We want to take the area starting at 40 pixels from the top, with the size of 640x920 pixels. The way mogrify do this, is using the –crop flag:
mogrify –crop 640x920+0+40 imagename.png
If we want contextually convert the image to the jpeg format we can add the ‘-format’ flag
mogrify -format jpg –crop 640x920+0+40 imagename.png
What about the thumbnails creation? You just need to add another flag, ‘-thumbnail’ with the maximum thumbnail’s width and height
mogrify -format jpg –crop 640x920+0+40 -thumbnail 120x120 imagename.png

For more information you can check the ImageMagick Web Site (www.imagemagick.org), or take a look at their books:





Here is the complete script. It assumes that you called the screenshots with the names: screenshot_iphone_n.png and screenshot_ipad_n.png (where n is the picture number, e.g., screenshot_iphone_1.png, screenshot_iphone_2.png, …), and it stores the thumbnails in a subdirectory.

#!/bin/sh
# Installation directory of ImageMagick (if not in PATH)
IMDIR='/ImageMagick-6.6.7/bin'
# Crop flag for iPhone with Retina Display
CROP='-crop 640x920+0+40'
# Crop flag for iPad
CROPIPAD='-crop 768x1004+0+20'
# Thumbnails directory
THUMBSDIR=thumbs
# Thumbnail flag
THUMB='-thumbnail 120x120'

# Adjust the screenshots
$IMDIR/mogrify -verbose -format jpg $CROP screenshot_iphone*.png
$IMDIR/mogrify -verbose -format jpg $CROPIPAD screenshot_ipad*.png

# Make the thumbnails
mkdir $THUMBSDIR
$IMDIR/mogrify -format jpg $CROP -path $THUMBSDIR $THUMB screenshot_iphone*.png
$IMDIR/mogrify -format jpg $CROPIPAD -path $THUMBSDIR $THUMB screenshot_ipad*.png