IPhone: Difference between revisions

From Wiki
Jump to navigation Jump to search
No edit summary
 
No edit summary
 
(One intermediate revision by the same user not shown)
(No difference)

Latest revision as of 22:31, 25 October 2024

Facts

  • iPhone Resolution: 320x480
  • top status bar is 20px, bottom tab bar is 44px
  • All images should be png

Basic Setup

  • Start by launching /Developer/Applications/Xcode
  • File -> New Project -> View-Based Application, choose name (e.g. MyProject)
  • Edit Objective-C code in Groups & FIles -> Classes with Xcode
  • Edit user interface with Groups & Files -> Resources -> MyProjectViewController.xib with Interface Builder. Drag elements from the Library window to the View window.
  • Click Build and Run in Xcode to test.

Application Icon

  1. Create a 57x57 png file
  2. Drag from Finder to Xcode Resources folder
  3. Choose "Copy" to create a copy in the project directory
  4. Click the Resources -> Info.plist file
  5. Next to "Icon File", enter the name of the png.

Interface Builder hints

  • The MyProjectViewController.xib window has three "View Mode" buttons. Use the middle one to drill down and select overlapped or hidden View elements.
  • When a View element is selected, double click it or use Command-1 to edit attributes. (Command is the clover-shaped button)
  • Hold the Option key when mousing over View elements to see more properties.
  • If you have an existing element in the View that you want to duplicate, Option-drag it to get a copy.

Outlet

  • Communicate from code to view with an IBOutlet. In header file:
IBOutlet UILabel *statusText;
  • An outlet must be defined in the header file before it can be accessed in Interface Builder.
  • Control-drag from File's Owner to the element and choose the corresponding outlet.

Action

  • Communicate from view to code with an IBAction. In header file:
- (IBAction)doSomething:(id)sender;
  • Select element and bring up connections inspector (Tools->Connections or Command-2).
  • Choose the desired event by clicking the circle to the left of it.
  • Drag circle to File's Owner and select the desired action.

Basic Interaction Sample App

MyProjectViewController.h:

#import <UIKit/UIKit.h>
@interface MyProjectViewController : UIViewController {
    IBOutlet UILabel *statusText;
}
@property (retain, nonatomic) UILabel *statusText;
-(IBAction)buttonPressed:(id)sender;
@end

MyProjectViewController.m:

#import "MyProjectViewController.h"
@implementation MyProjectViewController
@synthesize statusText;
-(IBAction)buttonPressed:(id)sender {
    NSString *title = [sender titleForState:UIControlStateNormal];
    NSString *newText = [[NSString alloc] initWithFormat: @"%@ button pressed.", title];
    statusText.text = newText;
    [newText release];
}
...boilerplate...
-(void)dealloc {
    [statusText release];
    [super dealloc];
}
@end
View:
  1. Double-click MyProjectViewController.xib in the Resources directory.
  2. Create a Label with no text and two RoundRect buttons named "Left" and "Right".
  3. Control-click on "File's Owner" in the xib window and drag it to the Label object in the view window. Let go of the mouse button and choose "statusText" from the Outlets popup menu.
  4. Select the Left button by clicking it; then open the Connection Inspector from Tools menu.
  5. Find Events -> TouchUpInside
  6. Click the circle next to TouchUpInside and drag to the "File's Owner" icon. Select "buttonPressed" from the popup menu.
  7. Do the same for the Right button.
  8. Build and Run

User Interface Elements

Label

Has a "text" attribute that you can change with an outlet. See the example above.

Image
  1. Drag a png file from Finder to the Resources folder in Xcode to import the image.
  2. Drag an ImageView element into the View
  3. Open attributes and tell it which png file to use
  4. Select "Size to Fit" from the Layout menu so the ImageView object is the same size as the imported image.
  5. Choose Drawing->Opaque to speed up drawing if there is no background
Text field

In MyProjectViewController.h:

#import <UIKit/UIKit.h>
@interface MyProjectViewController : UIViewController {
    IBOutlet UITextField *nameField;
}
@property (nonatomic, retain) UITextField *nameField;
- (IBAction)textFieldDoneEditing:(id)sender;  // make sure the text field gives up control when done editing
@end

In MyProjectViewController.m:

...
@implementation MyProjectViewController
@synthesize nameField;
- (IBAction)textFieldDoneEditing:(id)sender {  // make sure the text field gives up control when done editing
    [sender resignFirstResponder];
}
...

In Interface Builder

Outlet: Control-drag from File's Owner to the text field and choose the corresponding outlet.

Action: Select text field and bring up connections inspector. Choose the "Did End on Exit" event. Drag circle to File's Owner and select "textFieldDoneEditing" action.


Number field

Same as text field but you need a background click action to allow the user to leave the field when done editing. Add the method declaration to both header and implementation file. Here is the implementation:

- (IBAction)backgroundClick:(id)sender {
	[numberField resignFirstResponder];
	// add the same for any other edit fields that should lose focus
}

View:

  1. Use a Round Rect Button in the view and drag its edges to cover the entire screen.
  2. Use Layout->Send to Back to put it behind everything else.
  3. Then change its Type to Custom to make it disappear altogether.
  4. Tie the Touch Up Inside event to File's Owner backgroundClick action.
Slider

Use the "Value Changed" event to call the sliderChanged action. Access slider value with slider.value. Sample code:

-(IBAction)sliderChanged:(id)sender {
	UISlider *slider = (UISlider *)sender;
	int progressAsInt = (int)(slider.value + 0.5f);
	NSString *newText = [[NSString alloc] initWithFormat:@"%d", progressAsInt];
	sliderLabel.text = newText;
	[newText release];
}
Switch

Get value from switch.isOn. Use "Value Changed" event.

Segmented Control

Get value from segmentedControl.selectedSegmentIndex

SubView

Group elements inside a sub view. Hide all with subview.hidden = YES

Action Sheet

Modal dialog to force the user to choose an option. Use UIActionSheetDelegate protocol:

...
@interface MyProjectViewController : UIViewController <UIActionSheetDelegate> {
...

Create an Action Sheet in an action method:

UIActionSheet *actionSheet = [[UIActionSheet alloc]
	initWithTitle:@"Are you sure?"
	delegate:self
	cancelButtonTitle:@"No way!"
	destructiveButtonTitle:@"Yes, I'm sure!"
	otherButtonTitles:nil];
[actionSheet showInView:self.view];
[actionSheet release];

Handle the action sheet response with this method:

-(void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex {
	if (buttonIndex == [actionSheet cancelButtonIndex] { /* do cancel action, if any */ }
	else { /* do destructive (positive) action */}
}
Custom Button

To get nicer looking buttons, create a Round Rect button and then change its type to Custom. Download a nice looking button template from the web:

http://developer.apple.com/iphone/library/samplecode/UICatalog/index.html

Then implement the viewDidLoad method of UIViewController:

-(void)viewDidLoad {
	jmUIImage *buttonImage = [UIImage imageNamed:@"whiteButton.png"];
	UIIMage *stretchableButtonImage = [buttonImage stretchableImageWithLeftCapWidth:12 topCapHeight:0];
	[doSomethingButton setBackgroundImage:stretchableButtonImage forState:UIControlStateNormal];
}

Can also make the button change when pressed by using a different background image for state UIControlStateHighlighted

Autorotation

Controlled from the

-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

Available orientations:

  • UIInterfaceOrientationPortrait
  • UIInterfaceOrientationPortraitUpsideDown
  • UIInterfaceOrientationLandscapeLeft
  • UIInterfaceOrientationLandscapeRight

There are three different approaches to autorotation:

Autosize

Give elements autosize properties using the size inspector (command-3).

Restructure

Create outlets for each element; then call something like

element.frame = CGRectMake(x1, y1, width, height)

to resize/relocate each on rotation in the

-(void)willAnimateSecondHalfOfRotationFromInterfaceOrientation

method using self.interfaceOrientation as the "to" orientation.

Animating a rotation
[UIView beginAnimations:@"move buttons" context:nil];
... CGRectMake calls to move stuff around ...
[UIView commitAnimations];
Swap views
  • Create portrait and landscape outlets in the .h file. Save.
  • Delete the default view from the project.
  • Drag two or more View elements from the library and give them names like "portrait" and "landscape".
  • Use the size inspector to update the geometry (480x300 for landscape with top status bar).
  • Control-drag from File's Owner to each view and choose the related outlet.
  • Control-drag from File's Owner to portrait and choose the View outlet to choose it as default
  • Create this method in the .m file:
-(void)willAnimateFirstHalfOfRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
    duration:(NSTimeInterval)duration {
	if (toOrientation == UIInterfaceOrientationPortrait){
		self.view = self.portrait;
		self.view.transform = CGAffineTransformIdentity;
		self.view.transform = CGAffineTransformMakeRotation(0);  // In radians
		self.view.bounds = CGRectMake(0, 0, 300, 480);
...
  • Transform angles are:
    • 0 for portrait
    • M_PI/2 for landscape right
    • M_PI for upside down
    • -M_PI/2 for landscape left
  • Link in the CoreGraphics framework to support the transform:
    • Click Frameworks under the Groups and Files pane
    • Project -> Add to Project menu
    • /Developer/Platforms/iPhoneSimulator/Developer/SDKs/iPhoneSimulator3.1.sdk/System/Library/Frameworks/CoreGraphics.framework
    • uncheck "Copy items to destination..."
    • Reference type should be "Relative to current SDK"