Thứ Sáu, 30 tháng 7, 2010

Touch Tutorial - Part One (touchesEnded Event)

Welcome to the first part of Multi Touch tutorial series. In this tutorial I will show you how you can respond to a tap event.
First tutorial in this series, I will show how to zoom and image in and out. This is how the application will look like.

To get started, we have to
  1. Create a new project by selecting "Windows-based Application"
  2. Create a new UIView using IB and name it ImgView.
  3. Create a new file in XCode by selecting File -> New File -> UIViewController sub class and name it "ImgViewController".
  4. In IB, select File's owner object of the "ImgView" nib file and select Tools -> Identity Inspector. Under Class Identity select "ImgViewContoller" as the class.
  5. Select Tools - > Connections Inspector and create a connection from the view property to the view object in IB.
  6. Place a UIImageView on the view we just created.
  7. Add a image to the resource folder, to be used by the UIImageView.
  8. Select the Image and select Tools -> Attributes Inspector in IB. From the Image drop down select your image.
  9. Set the Mode to Center.
  10. Un-check "User Interaction Enabled" and "Multiple Touch".
  11. Select the view and select "Multiple Touch" in the Attributes Inspector. Note that "User Interaction Enabled" should already be checked, if not check it.
Using the last two settings all the touches events will be sent to ImgViewController. Since we need to control the image, we need a variable of type UIImageView. This is how the header file of "MultiTouchTutorialAppDelegate" will look like.

#import >

@class ImgViewController;

@interface MultiTouchTutorialAppDelegate : NSObject {
UIWindow *window;
ImgViewController *ivController;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;

@end


Using IB, select File's owner object and open Tools -> Connections Inspector. Create a connection from the imgView to the UIImageView placed on the view. Now we will be able to control the UIImageView from code.

Now we need to add the view "ImgView" as a subview in applicationDidFinishLaunching method. This is how the source code will look like

- (void)applicationDidFinishLaunching:(UIApplication *)application {

ivController = [[ImgViewController alloc] initWithNibName:@"ImgView" bundle:[NSBundle mainBundle]];

[window addSubview:[ivController view]];

// Override point for customization after application launch
[window makeKeyAndVisible];
}


Click on Ctrl+return to run the application in simulator. You should see the image loaded in the simulator.

Right now the application does not respond to any events, but all we have to do is implement some methods. Let's implement the touchesEnded method which will be called when touches are ended.

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
}


In this method we will respond to a single tap and double tap. On single tap we will zoom out the image and on double tap we will set the mode to "Center", which is doing the same as in step 9.

This is how the code looks like

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {

//Get all the touches.
NSSet *allTouches = [event allTouches];

//Number of touches on the screen
switch ([allTouches count])
{
case 1:
{
//Get the first touch.
UITouch *touch = [[allTouches allObjects] objectAtIndex:0];

switch([touch tapCount])
{
case 1://Single tap
imgView.contentMode = UIViewContentModeScaleAspectFit;
break;
case 2://Double tap.
imgView.contentMode = UIViewContentModeCenter;
break;
}
}
break;
}

}


We get all the touches from the event into allTouches variable. We thenfind out how many fingers were touching the screen, since in our case we only want to zoom in and out, it seems normal to assume that the user will only be using one finger. We then find out how many tocuhs are touching the screen by calling the count method of allTouches variable. If there is only one finger touching the screen, we get the Touch object at index zero and find out the tap count of that object. If the tap count is one we will zoom out the image and if it is two we are going to zoom in. We zoom out the image by setting the contentMode to UIViewContentModeScaleAspectFit and zoom in the image by setting it to UIViewContentModeCenter.

In this tutorial we learnt how to respond to touchesEnded event and in the ftuture tutorials we will learn ho wto respond to touches began, touches moved and touches cancelled.

You can download the source code for this tutorial here. Please leave me your comments and let me know your thoughts.

Touch Tutorial - Part Two (touchesBegan Event)



In the second part of the touch tutorial series, I will show you how can you use the touchesBegan event. It is recommended that you read the first tutorial in this series. You can download the source code for the first tutorial here.

This is the method which we will implement in ImgViewController.m file.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
}


In this method we will display an alert if the user has touched the image for 2 seconds. This how the source code will look like

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

NSSet *allTouches = [event allTouches];

switch ([allTouches count]) {
case 1: { //Single touch

//Get the first touch.
UITouch *touch = [[allTouches allObjects] objectAtIndex:0];

switch ([touch tapCount])
{
case 1: //Single Tap.
{
//Start a timer for 2 seconds.
timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self
selector:@selector(showAlertView:) userInfo:nil repeats:NO];

[timer retain];
} break;
case 2: //Double tap.
break;
}
} break;
case 2: { //Double Touch

} break;
default:
break;
}

}


We get all the touches and for now we will only look at the code for single touch. Get the touch object at index 0 (since it is a single touch, there will be an object at this index) and find out the tap count. If the tap count is one then create a new timer for 2 seconds and give a method which will be called, when the timer is elapsed. The timer variable is declared in the header file of ImgViewController.h file. "showAlertView" is the method which is called when the user presses the screen for 2 seconds.

To display an alert view, we need to implement the UIAlertViewDelegate. This is how the header file will be changed
#import


@interface ImgViewController : UIViewController {

IBOutlet UIImageView *imgView;
NSTimer *timer;

}

@end


this is how "showAlertView" method will look like

-(void) showAlertView:(NSTimer *)theTimer {

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Birth of a star" message:@"Timer ended. Event Fired."
delegate:self cancelButtonTitle:@"OK" otherButtonTitles: nil];
[alert show];
[alert release];

}


We do need to cancel the timer if any other method like touchesMoved, touchesEnded or touchesCanceled is called. We do this by first checking if the timer is active or not, if it is active then we call the "invalidate" method. This is to be done at the beginning of all the three methods mentioned.

Run this application in the simulator and see it working. The same technique can be used to display an alert sheet or any custom action that you want to perform.

You can download the source code from here and please leave me your comments.

Touch Tutorial - Part Three (Zoom In/Out)

In this tutorial I will show how to implement the pinch feature (zoom in/out).


In this tutorial, I will show you how to use the touchesMoved event to zoom in and out the image on the UIImageView. Now, I have not exactly figured out a way to actually zoom in and out the actual image but here is the code on when to zoom in and zoom out. If anyone has figured out a way to zoom in/out the actual image, please share it everyone.

Before we can implement the touchesMoved event, we are going to declare some variables and methods in ImgViewController.h file. This is how the header file is going to look like

#import


@interface ImgViewController : UIViewController {

IBOutlet UIImageView *imgView;
NSTimer *timer;
CGFloat initialDistance;

}

- (CGFloat)distanceBetweenTwoPoints:(CGPoint)fromPoint toPoint:(CGPoint)toPoint;
- (void) clearTouches;

@end


disanceBetweenTwoPoints is used to calculate as the method name implies, distance between two points. initialDistance is used to keep track of the distance when touchesBegan method is fired. To zoom in and zoom out, we first need to calculate the distance between the two fingers and store it in initialDistance variable. This is how the touchesBegan method will look like.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {

NSSet *allTouches = [event allTouches];

switch ([allTouches count]) {
case 1: { //Single touch

//Get the first touch.
UITouch *touch = [[allTouches allObjects] objectAtIndex:0];

switch ([touch tapCount])
{
case 1: //Single Tap.
{
//Start a timer for 2 seconds.
timer = [NSTimer scheduledTimerWithTimeInterval:2 target:self
selector:@selector(showAlertView:) userInfo:nil repeats:NO];

[timer retain];
} break;
case 2: {//Double tap.

//Track the initial distance between two fingers.
UITouch *touch1 = [[allTouches allObjects] objectAtIndex:0];
UITouch *touch2 = [[allTouches allObjects] objectAtIndex:1];

initialDistance = [self distanceBetweenTwoPoints:[touch1 locationInView:[self view]]
toPoint:[touch2 locationInView:[self view]]];
} break;
}
} break;
case 2: { //Double Touch

} break;
default:
break;
}

}


We get the first touch objects at index 0 and 1 and then we calculate the initial distance between the two points. This is how the distanceBetweenTwoPoints method looks like

- (CGFloat)distanceBetweenTwoPoints:(CGPoint)fromPoint toPoint:(CGPoint)toPoint {

float x = toPoint.x - fromPoint.x;
float y = toPoint.y - fromPoint.y;

return sqrt(x * x + y * y);
}


In touchesMoved event, we find out if there are at least two touches on the screen. We then get the touch object at index 0 and 1, calculate the distance between the finalDistance and the initialDistance. If the initialDistance is greater then the finalDistance then we know that the image is being zoomed out else the image is being zoomed in. This is how the source code looks like

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {

if([timer isValid])
[timer invalidate];

NSSet *allTouches = [event allTouches];

switch ([allTouches count])
{
case 1: {

} break;
case 2: {
//The image is being zoomed in or out.

UITouch *touch1 = [[allTouches allObjects] objectAtIndex:0];
UITouch *touch2 = [[allTouches allObjects] objectAtIndex:1];

//Calculate the distance between the two fingers.
CGFloat finalDistance = [self distanceBetweenTwoPoints:[touch1 locationInView:[self view]]
toPoint:[touch2 locationInView:[self view]]];

//Check if zoom in or zoom out.
if(initialDistance > finalDistance) {
NSLog(@"Zoom Out");
}
else {
NSLog(@"Zoom In");
}

} break;
}

}


NSLog tells us if what we are doing is correct or not. If someone knows how to zoom in/out an actual image, please let me know.

Since we keep track of the initialDistance, we need to clear that value when touches is canceled or when touches are ended. We do this in clearTouches method, which is called from touchesEnded event and touchesCanceled event. This is how the method looks like

- (void)clearTouches {

initialDistance = -1;
}


I hope you found this tutorial a little helpful without the actual zoom in/out functionality. You can download the source code here and please leave me your comments.

TouchTutorial - Part Four (pan left/right)



Welcome to the fourth part of the tutorial where we will see how to pan an image (move left or right). This tutorial borrows its source code from its predecessors.

What we want to do is move the image left or right when the user swipes his fingers in either direction. We do this in touchesMoved method. This is how the source code will look like

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {

if([timer isValid])
[timer invalidate];

NSSet *allTouches = [event allTouches];

switch ([allTouches count])
{
case 1: {
//The image is being panned (moved left or right)
UITouch *touch = [[allTouches allObjects] objectAtIndex:0];
CGPoint centerPoint = [touch locationInView:[self view]];

[imgView setCenter:centerPoint];

} break;
case 2: {
//The image is being zoomed in or out.

UITouch *touch1 = [[allTouches allObjects] objectAtIndex:0];
UITouch *touch2 = [[allTouches allObjects] objectAtIndex:1];

//Calculate the distance between the two fingers.
CGFloat finalDistance = [self distanceBetweenTwoPoints:[touch1 locationInView:[self view]]
toPoint:[touch2 locationInView:[self view]]];

//Check if zoom in or zoom out.
if(initialDistance > finalDistance) {
NSLog(@"Zoom Out");
}
else {
NSLog(@"Zoom In");
}

} break;
}

}


Since only one touch is required to move the image left or right, the following code is executed when the total number of touches is one. We get the first touch and then get the position of the touch. We move the image by setting the position of the touch as the center of the UIImageView.

I hope this tutorial helped you learning better how to use the touch features of the iPhone SDK. The same basic primniple can be used in any kind of application.

The source code can be downloaded from here and please leave me your comments.

Thứ Tư, 28 tháng 7, 2010

How to make an Orientation-Aware Clock

How To Make An Orientation-Aware Clock

iphone_clock

For this tutorial we’re going to build a simple clock that is orientation-aware, meaning that when you rotate your iPhone, the time rotates with it. I’m assuming you have a basic knowledge of the iPhone SDK.

To get started, you will need a label for the time and a background image. You will also need a timer. To get started, you must declare your outlets in code before Interface Builder will be able to use them. I’ll show you how to do that now.

Let’s Get Our Hands in Some Code

Edit SimpleClockViewController.h so it looks like this:

1#import
2
3@interface SimpleClockViewController : UIViewController {
4 IBOutlet UILabel* clockLabel;
5 NSTimer *myTicker;
6}
7
8@end

The myTicker is going to be responsible for updating the clockLabel. We will implement that code later.

The next thing you want to do is drag background_image.png to your project (see image below). You can get the image here.

image-510

You want to copy the item to the project’s directory so put a check mark next to “Copy items into destination group’s folder (if needed).” Your settings should look similar to this. Click Add.

2009-03-09_1229

Open SimpleClockViewController.xib. Drag UIImageView from the Library to the View window. This will act as a placement holder for our background image.

image-5101

Bring up the Attributes Inspector. Set the Image to background_image.png. Set the Mode to Scale To Fill so that the background_image.png stretches out when we rotate the iPhone.

2009-03-06_15431

Bring up the Size Inspector and change the Autosizing settings to look like this. The arrows in the Autosizing box act as outward springs, which cause the view to resize itself proportionally based on the width or height of its superview. The “I”s act as struts that keep a fixed distance when the View is changed when you rotate the iPhone. If that’s hard to visualize, Interface Builder has an animation to the right of the Autosizing box will help you visualize its current settings.

2009-03-06_1545

Drag a Label to the View window and resize to approximately the width of the window. Center it. This makes the time larger and also positions the time to be rotated around its center point when you turn the iPhone into landscape mode.

image-5102

Change the font of the label by selecting the Label and hitting Command-T. Change the settings so you’re using Helvetica, Bold, size 48.

2009-03-06_15561

Bring up the Attributes Inspector. Change the Layout Alignment to Center. Again, we’re doing this so the time rotates around its center. Change the font color to white so it looks good on the dark background. It should look similar to this:

2009-03-06_1557

Bring up the Size Inspector and change your Autosizing settings to look like the image below. This makes sure the time rotates and positions itself correctly around its center.

2009-03-06_1557a

Lastly, Control-Drag from File’s Owner to the Label and choose clockLabel when the outlet box pops up. This tells your Label which variable it is in the code.

2009-03-09_1311

Save and close Interface Builder. Back in Xcode, open SimpleClockViewController.h and add runTimer and showActivity methods. These declare the functions we’re going to write.

01#import
02
03@interface SimpleClockViewController : UIViewController {
04 IBOutlet UILabel* clockLabel;
05 NSTimer *myTicker;
06}
07
08/* New Methods */
09- (void) runTimer;
10- (void)showActivity;

Open SimpleClockViewController.m and add the methods we just declared.

01- (void)runTimer {
02 // This starts the timer which fires the showActivity
03 // method every 0.5 seconds
04 myTicker = [NSTimer scheduledTimerWithTimeInterval: 0.5
05 target: self
06 selector: @selector(showActivity)
07 userInfo: nil
08 repeats: YES];
09
10}
11
12// This method is run every 0.5 seconds by the timer created
13// in the function runTimer
14- (void)showActivity {
15
16 NSDateFormatter *formatter =
17 [[[NSDateFormatter alloc] init] autorelease];
18 NSDate *date = [NSDate date];
19
20 // This will produce a time that looks like "12:15:00 PM".
21 [formatter setTimeStyle:NSDateFormatterMediumStyle];
22
23 // This sets the label with the updated time.
24 [clockLabel setText:[formatter stringFromDate:date]];
25
26}

The runTimer method only has 1 line of code split into multiple lines. All it does is call the showActivity method every 0.5 seconds.

The showActivity method formats the clockLabel so it looks like “12:15:00 PM” and sets it to the current time. As mentioned above, this method is called every 0.5 seconds.

We want to call runTimer after the view loads. This is a common method that, when Xcode generated SimpleClockViewController.m, they included a method called viewDidLoad. This method is called immediately after the View items are loaded. Find the viewDidLoad method and uncomment it.

Add [self runTimer]; to the end of the method. It should now look like this:

1// Implement viewDidLoad to do additional
2// setup after loading the view, typically from a nib.
3- (void)viewDidLoad {
4 [super viewDidLoad];
5
6// This calls the runTimer method after loading
7// SimpleClockViewController.xib
8 [self runTimer];
9}

When Xcode generated SimpleClockViewController.m, they also included shouldAutorotateToInterfaceOrientation. By default, views display only in portrait orientation, so you need to implement shouldAutorotateToInterfaceOrientation method if you want to support other orientations.

Locate the shouldAutorotateToInterfaceOrientation method and uncomment it. You can support only some orientations such as portrait or landscape with Home button on the right, but we don’t need to limit ourselves to those scenarios. We want to support all orientations so the view rotates correctly no matter how we’re holding the iPhone. To do this, replace return (interfaceOrientation == UIInterfaceOrientationPortrait); with return YES;.

1// Override to allow orientations other than
2// the default portrait orientation.
3- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
4 // Return YES for supported orientations
5 return YES;
6}

Now you can build and run it! Hit Command-Left to see your UI rotate with the iPhone simulator. You can Build and Run the project to make sure everything is compiling and running.

Thứ Hai, 26 tháng 7, 2010

Gradient UITableView backgrounds

iPhone SDK Tutorial: How to create gradient UITableView backgrounds

This demonstration provides an example of how to spice up your UITableView rows for a more polished look. In addition to seeing how easy it can be to design a nice graphic for your iPhone app, you get a start to finish implementation.

This video was embedded using the YouTuber plugin by Roy Tanck. Adobe Flash Player is required to view the video.
The finished product is shown below.

Rather than sticking with stock components included in Interface Builder, this demonstration shows a simple technique that gives your app a more professional look. As a developer, it can be difficult to create nice looking graphics for your app. Hiring a designer can quickly exceed the budget. However, creating some nice looking graphics is certainly achievable as a beginning designer. In addition to picking up some new great skills, a polished off UI can lend more creditability to your app and provide an overall better user experience.

In the demo, Photoshop Elements is used, which is 80 bucks at adobe.com with a mail-in rebate. To get started, create a new image with these values:

  • Width: 80 pixels
  • Height: 40 pixels
  • Background Contents: Transparent

Select a foreground color from the toolbar, as shown below:

Now select the gradient button, as shown below:

With the gradient selected, swipe from bottom to top on your image. This should produce a gradient color. Now choose File and “Save for Web”. You’ve just created the image we’ll use in our tableview. Let’s switch over to Xcode and implement the image.

In Xcode, we start by creating a navigation based application.

Once the application has been created, add the newly created image by right clicking the Resources folder then “Add” and “Existing Files”, as shown below:

The following code snippet creates two views. Both are then added to the cell’s view. Because the label, which is a view, is added as the last view, we need to ensure its background is transparent (clearColor). Otherwise, it will cover part or all (depending on the size we set) of our background image. Thinking about what this stack of layers will look like, below is a screenshot of the same scenario in Interface Builder:

From the screenshot, you can see the cell’s view owns the imageview and label. Although closer to the bottom, the label is actually top most to the user, hence the reason we need its background to clear.

Let’s take a look at the implementation in Xcode, which is all done in the UITableView delegate method cellForRowAtIndexPath:.

UIImage *image = [UIImage imageNamed:@"gradientcolor.png"];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
imageView.contentMode = UIViewContentModeScaleToFill;
cell.backgroundView = imageView;
[imageView release];

UILabel *label = [[UILabel alloc] init];
label.text = @"testing colors";
label.frame = cell.bounds;
label.backgroundColor = [UIColor clearColor];
label.textAlignment = UITextAlignmentCenter;
[cell addSubview:label];
return cell;

In the above snippet, we create an image object using the image we added to our app bundle. Next, we create a UIImageView object with the newly created image. The image view will be assigned to our cell’s background view. The backgroundView will retain an instance of the imageView. Therefore, we release our instance, as follows:

[imageView release];

If we had not released our instance, we’d have two instances of the imageView in memory and thus a memory leak. Moving on down in the code, we create an instance of a label. We set the label’s size to cover the entire cell. The label’s background is set to clear or transparent so it doesn’t hide the cell’s background image. Our assigned text is centered and finally, we add the label to the cell’s view, making it the top most view in the cell.

Thứ Hai, 19 tháng 7, 2010

iPad - Helloworld

Nguon: http://icodeblog.com/2010/04/05/ipad-programming-tutorial-hello-world/

Introduction

Now, that the iPad has been released, I’m sure you are all scrambling for ideas on how to snag a piece of the maket in the imminent gold rush. iCodeBlog is going to help you on your journey with a series of iPad tutorials to come.

Since the iPad uses the same SDK as the iPhone, all of the code under the hood is almost identical. Actually, when looking at the new and changed API classes, you will realize that most of them are user interface related. This is good news for us since we have already been coding iPhone.

While this tutorial is called “Hello World”, it is really much more than that. I assume you already have working knowledge of iPhone/Objective-C programming.

What We Will Be Creating

In today’s tutorial, I will be showing you how to create an iPad project that uses the UISplitViewController to display content in 2 separate panes. We will also be touching on some of the new design/UI patterns and giving an overall introduction to iPad programming.

The project will be based on one of my earliest tutorials that displayed a list of fruit in a UITableView and drilled down when they were selected. We will be expanding on that example and creating something that will look like this.









It uses a UISplitViewController to display a UITableView on the left and a UIView with a UIImageView subview on the right. This project is actually quite simple to create as the template code provides much of the code we need to get started.

Getting Started

1. Make sure you have downloaded the 3.2 SDK form http://developer.apple.com/iphone/. The iPad simulator will come with this download.

2. Download the resources needed for this project and unzip them iPadHelloWorldResources.zip . (contains image files and a plist we will be using to load the images)

Creating The Project

Starting a project for the iPad is no different than starting one for the iPhone. When you open XCode and select File->New Project, you should notice the addition of a Split View-Based Application. Select this and name it iPadHelloWorld.

This will create a basic application with a UITableView on the left and a UIView on the right. It will even populate the table with some sample elements. It will add the following files to your project.

Here is a brief description of each of these files:

  • iPadHelloWorldAppDelegate – This is similar to every app delegate. If you look in the application:didFinishLaunchingWithOptions method, you will see that the UISplitViewController is being allocated with the MasterViewController and DetailViewControllers.
  • MasterViewController – A UITableViewController, nothing fancy. It will be handling the view on the left hand side.
  • DetailViewController – This handles the content view that you see on the right hand side. We will be updating this as the user selects different rows in the table to the left. This simply houses a single view.

Go ahead and press Build and Run to check out the application. If you haven’t already done so, play around with the iPad contacts and settings apps as well.

Note: When you launch the application, you will only see the main view since the simulator runs in vertical mode. To see the views side-by-side, rotate the simulator by clicking “Hardware -> Rotate Left/Right”. You can also press CMD->Arrow Left/Right on the keyboard.

Importing The Project Images

Once you have had some time to play with the new iPad project, you will now need to import the images needed for this project. After downloading and unzipping the files in from this tutorial, drag them into the project folder called “Resources-iPad”.

XCode will prompt you to copy the files, check yes and click OK.

Make sure you include all 4 images files as well as the file named fruits.plist.

Displaying The List Of Fruits

Displaying our fruits list is no different than displaying data in any other UITableView. Let’s begin by opening MasterViewController.h and adding a declaration for our fruits array.

#import 


@class DetailViewController;

@interface MasterViewController : UITableViewController {
DetailViewController *detailViewController;
NSArray * fruits;
}

@property (nonatomic, retain) IBOutlet DetailViewController *detailViewController;
@property (nonatomic, retain) NSMutableArray *fruits;

@end

As you can see, there is nothing new here. We simply declare our fruits array and create a property for it.

We will be loading the fruits from the plist file that you imported into your project in the last step. Loading content from a plist file is a very quick and easy solution when you don’t require a database.

Open up MasterViewController.m and add the following line of code to your viewDidLoad method.

- (void)viewDidLoad {

[super viewDidLoad];
self.fruits = [[NSArray arrayWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"fruits" ofType:@"plist"]] retain];
}

The file fruits.plist is essentially an array that has been written out to a file. If you open it up, it looks very similar to XML. Now that our fruits array has been populated, let’s implement each of the UITableView delegate and datasource methods to populate the table.

UITableView datasource methods

- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section {

// Return the number of rows in the section.
return [fruits count];
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *CellIdentifier = @"CellIdentifier";

// Dequeue or create a cell of the appropriate type.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
cell.accessoryType = UITableViewCellAccessoryNone;
}

// Get the object to display and set the value in the cell.
cell.textLabel.text = [self.fruits objectAtIndex:indexPath.row];
return cell;
}
Advertisement Nothing special… We first tell the tableview that we want fruits.count (4 in this case) number of rows.

Next, we display the name of the fruit in each tableview cell. If you want to learn more on UITableViews, read this tutorial.

UITableView delegate methods

- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {


/*
When a row is selected, set the detail view controller's detail item to the item associated with the selected row.
*/

detailViewController.detailItem = [self.fruits objectAtIndex: indexPath.row];
}

Here, we are simply setting the detailItem property of the detailViewController to the selected fruit. We will discuss this property later in this section, but for now all you need to know is that its type is id.

At this point, go ahead and press Build and Run to see your code in action. You should see something that looks like this:

It displays the list of fruits, but nothing happens when you select a cell (well the title of the detailView may change).

Now that we have our list of fruits displayed, we now need to implement the code to display their corresponding image.

Displaying The Fruits

Displaying the selected fruit is actually quite simple. The first thing we need to do is add a UIImageView to our detailView.

Start by adding the IBOutlet for the image view. Open up DetailViewController.h and add the following code:

@interface DetailViewController : UIViewController  {


UIPopoverController *popoverController;
UINavigationBar *navigationBar;

id detailItem;

IBOutlet UIImageView * fruitImageView;
}

@property (nonatomic, retain) UIPopoverController *popoverController;
@property (nonatomic, retain) IBOutlet UINavigationBar *navigationBar;

@property (nonatomic, retain) id detailItem;

@property (nonatomic, retain) IBOutlet UIImageView * fruitImageView;

@end

All of the code here comes with the template except the code to add the IBOutlet UIImageView. Once you have added this open up DetailView.xib in interface builder.

Add a UIImageView on to the view and size it to 500×500.

Now, click on the File’s Owner object and open the connection inspector (Tools -> connection inspector).

Drag from your imageView IBOutlet to the UIImageView and release. The UIImageView is now connected to your outlet.

Note: If you want the images to not skew, set the content mode of the image view (in the attributes inspector) to Aspect Fit.

Now that the imageview has been connected, it’s time to write the code that updates it. Close Interface Builder and open the file DetailViewController.m and add the following lines to the setDetailItem method:

- (void)setDetailItem:(id)newDetailItem {

if (detailItem != newDetailItem) {
[detailItem release];
detailItem = [newDetailItem retain];

// Update the view.
navigationBar.topItem.title = detailItem;
NSString * imageName = [NSString stringWithFormat:@"%@.png",detailItem];
[self.fruitImageView setImage:[UIImage imageNamed:imageName]];
}

if (popoverController != nil) {
[popoverController dismissPopoverAnimated:YES];
}
}

Most of this code has been added by the template and I won’t discuss it too much in this tutorial. But for now, the important additions are the lines that load the image based on the name of the fruit and the one below it that sets the image property of the image view.

There you have it! Build and go and the application should function as mentioned. Here is another screenshot of the final product.

Another Cool Feature Of SplitViewController

When in vertical mode, the SplitViewController gives you another new UI element called the UIPopOverView. Collin will have a tutorial up soon on this view, but the figure below shows you what I’m talking about.

When the device is vertical, it will automatically rotate your view and provide a UIPopoverView when the “Master List” button is pretty. (BTW this button is also customizable).

You may download the source for this tutorial here iPadHelloWorld.zip.

If you have questions, post them here or ask me on Twitter.

Happy iCoding!

Thứ Sáu, 16 tháng 7, 2010

OpenGL

OPenGL - Sample drawing

Chú ý:
Định nghĩa 2 cấu trúc Vertex3D và Triangle3D (nên đn trong 1 file .h rồi import vào) :
* Created by VUONGTM on 7/16/10.
* Copyright 2010 EXARTISAN. All rights reserved.
*This is my definition
*/

/*
*Vertex3D
**/
typedef struct {
GLfloat x;
GLfloat y;
GLfloat z;
} Vertex3D;

/*
* Make vertex
**/
static inline Vertex3D Vertex3DMake(CGFloat inX, CGFloat inY, CGFloat inZ)
{
Vertex3D ret;
ret.x = inX;
ret.y = inY;
ret.z = inZ;
return ret;
}

/*
*Canculate distance between two vertex
**/
static inline GLfloat Vertex3DCalculateDistanceBetweenVertices (Vertex3D first, Vertex3D second)
{
GLfloat deltaX = second.x - first.x;
GLfloat deltaY = second.y - first.y;
GLfloat deltaZ = second.z - first.z;
return sqrtf(deltaX*deltaX + deltaY*deltaY + deltaZ*deltaZ );
};


/*
*Triangle3D
**/
typedef struct {
Vertex3D v1;
Vertex3D v2;
Vertex3D v3;
} Triangle3D;

static inline Triangle3D Triangle3DMake(Vertex3D v1, Vertex3D v2, Vertex3D v3)
{
Triangle3D trigalge3d;
trigalge3d.v1 = v1;
trigalge3d.v2 = v2;
trigalge3d.v3 = v3;
return trigalge3d;
}

Thứ Ba, 13 tháng 7, 2010

Thay đổi mũi tên bên phải row của Table View (Navigation)

Khi chuyển màu nền của table view thành màu tối thì mũi tên bị mất do cùng màu, liệu có thể thay đổi màu ?
Thật không may, câu trả lời là không. Tuy nhiên có vài cách có thể khắc phục được
- Sử dụng image row.rightImage
- Dễ hơn là sử dụng cách sau:

Bổ sung (hoặc edit) phương thức vào lớp implement các sự kiện table view

- (UITableViewCellAccessoryType)tableView:(UITableView *)tableView accessoryTypeForRowWithIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellAccessoryDetailDisclosureButton;
}

Kết quả là sẽ nhận được một mũi tên trắng trong hình tròn xanh ( có thể nổi trên mọi màu nền)

Thứ Hai, 12 tháng 7, 2010

iPhone sample- nhieu vi du hay

http://www.edumobile.org/iphone/category/iphone-programming-tutorials/

iPhone - Marquees

How to create a marquee text for an iPhone app

Posted by: twmeier on Jan 21, 2010
Tagged in: Programming , iPhone

In this blog, you will learn how to create a moving text field (also know as a marquee). Marquees are very convenient to show news, stock updates, sport scores etc..


In the .h file:
#import
@interface FirstViewController : UIViewController {

UIView *messageView;
UILabel *lblTime;
CGSize messageSize;
}
@end


In the .m file:

- (void)viewDidAppear:(BOOL)animated {
NSString *theMessage = @"Hello, my name is Enigo Montoya. You killed my father, prepare to die";
messageSize = [theMessage sizeWithFont:[UIFont systemFontOfSize:14.0]];
messageView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, messageSize.width, 19)]; //x,y,width,height
[messageView setClipsToBounds:YES]; // With This you prevent the animation to be drawn outside the bounds.
[self.view addSubview:messageView];
lblTime = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, messageSize.width, 19)]; //x,y,width,height
[lblTime setBackgroundColor:[UIColor darkGrayColor]];
lblTime.font = [UIFont systemFontOfSize:14];
[lblTime setText:theMessage];
[lblTime setTextAlignment:UITextAlignmentLeft];
lblTime.frame = CGRectMake(0, 0, messageSize.width, 19); //x,y,width,height
[messageView addSubview:lblTime];
float duration = messageSize.width / 60; // This determines the speed of the moving text.
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:duration];
[UIView setAnimationTransition:UIViewAnimationTransitionNone forView:messageView cache:YES];
lblTime.frame = CGRectMake(-messageSize.width, 0, messageSize.width, 19); //x,y,width,height
[UIView commitAnimations];
}

Thats all there is too it. Check out the comments in the code for further clues on how it works.

Thứ Hai, 5 tháng 7, 2010

UIWebView in multi tab (tab bar)

UIWebView in a View Based App (Video)

iPhone Facebook Connect Tutorial

iPhone FBConnect: Facebook Connect Tutorial

Now a days social networking websites like facebook are becoming very popular, so integrating facebook with app has become a necessity to make you application popular. We are going to do the same through this tutorial. The Facebook Connect SDK provides code which third-party developers can embed into their applications to connect to their Facebook accounts and exchange information with iPhone apps. It’s a way of embedding “social context” to an iPhone app, according to Facebook.

Create a Viewbased Application with name ‘FacebookAPI’.

Prerequisite:
1.Download Facebook Connect for iPhone SDK (http://svn.facebook.com/svnroot/platform/clients/packages/fbconnect-iphone.zip) or you can download same from here
Just go through the project. In particular, the “Connect” sample project. Sample Project gives demo of some of the functionality.

1.1.Open src/FBConnect.xcodeproj from SDK that you downloaded, and your own project as well.

1.2.Drag n drop FBConnect group. Make sure “Copy items into destination group folder” is NOT checked. It should look as shown below

1.3.Go to Project Menu ->Edit project settings and scroll down to “User Header Search Path” add entry which will point to “src folder”

1.4.To test import all .m n .h files in case any miss. And compile.

2.Login to Facebook. After that go to Developers Page (http://www.facebook.com/developers/) as shown below.

3.Register your application with Facebook

3.1.Click on Set up New Application Button in the upper right hand corner.

3.2.Give Application name and click on create application button. Then you will see new application screen with detail including “API key”and “API Secret Key”

Note : This application will not work until you provide your Facebook application’s API keys.

Now to get started with actual coding:

Append Following code in FacebookAPIAppDelegate.h

01#import
02#import "FBConnect/FBConnect.h"
03#import "FBConnect/FBSession.h"
04
05@class FacebookAPIViewController;
06
07@interface FacebookAPIAppDelegate : NSObject {
08 UIWindow *window;
09 FacebookAPIViewController *viewController;
10 FBSession *_session;
11}
12
13@property (nonatomic, retain) IBOutlet UIWindow *window;
14@property (nonatomic, retain) IBOutlet
15 FacebookAPIViewController *viewController;
16@property (nonatomic,retain) FBSession *_session;
17@end

Append Following code in FacebookAPIAppDelegate.m

01#import "FacebookAPIAppDelegate.h"
02#import "FacebookAPIViewController.h"
03
04@implementation FacebookAPIAppDelegate
05
06@synthesize window;
07@synthesize viewController;
08@synthesize _session;
09
10- (void)applicationDidFinishLaunching:(UIApplication *)application {
11
12// Override point for customization after app launch
13[window addSubview:viewController.view];
14[window makeKeyAndVisible];
15}
16
17- (void)dealloc {
18 [_session release];
19 [viewController release];
20 [window release];
21 [super dealloc];
22}
23
24@end

Here in FacebookAPIAppDelegate we have just declared _session variable of type FBSession to keep track of the session and to check if session for current user exists or not.

Append Following code in FacebookAPIViewController.h

01#import
02
03#import "FBConnect/FBConnect.h"
04#import "FBConnect/FBSession.h"
05
06@interface FacebookAPIViewController : UIViewController {
07 FBLoginButton *loginButton;
08 UIAlertView *facebookAlert;
09 FBSession *usersession;
10 NSString *username;
11 BOOL post;
12}
13
14@property(nonatomic,retain) FBLoginButton *loginButton;
15@property(nonatomic,retain) UIAlertView *facebookAlert;
16@property(nonatomic,retain) FBSession *usersession;
17@property(nonatomic,retain) NSString *username;
18@property(nonatomic,assign) BOOL post;
19
20- (BOOL)textFieldShouldReturn:(UITextField *)textField;
21-(void)getFacebookName;
22-(void)postToWall;
23
24@end

Append Following code in FacebookAPIViewController.m

01#import "FacebookAPIViewController.h"
02#import "FacebookAPIAppDelegate.h"
03
04#define _APP_KEY @"Your API Key Goes here"
05#define _SECRET_KEY @"Your Secrete Key Goes here"
06
07@implementation FacebookAPIViewController
08@synthesize loginButton;
09@synthesize facebookAlert;
10@synthesize usersession;
11@synthesize username;
12@synthesize post;
13
14- (void)viewDidLoad {
15 FacebookAPIAppDelegate *appDelegate =
16 (FacebookAPIAppDelegate *) [[UIApplication
17 sharedApplication]delegate];
18 if (appDelegate._session == nil){
19 appDelegate._session = [FBSession
20 sessionForApplication:_APP_KEY
21 secret:_SECRET_KEY delegate:self];
22 }
23 if(self.loginButton == NULL)
24 self.loginButton = [[[FBLoginButton alloc] init] autorelease];
25 loginButton.frame = CGRectMake(0, 0, 100, 50);
26 [self.view addSubview:loginButton];
27
28 [super viewDidLoad];
29}
30
31- (void)dealloc {
32 [username release];
33 [usersession release];
34 [loginButton release];
35 [super dealloc];
36}
37
38- (void)session:(FBSession*)session didLogin:(FBUID)uid {
39 self.usersession =session;
40 NSLog(@"User with id %lld logged in.", uid);
41 [self getFacebookName];
42}
43
44- (void)getFacebookName {
45 NSString* fql = [NSString stringWithFormat:
46 @"select uid,name from user where uid == %lld",
47 self.usersession.uid];
48 NSDictionary* params =
49 [NSDictionary dictionaryWithObject:fql
50 forKey:@"query"];
51 [[FBRequest requestWithDelegate:self]
52 call:@"facebook.fql.query" params:params];
53 self.post=YES;
54}
55
56- (void)request:(FBRequest*)request didLoad:(id)result {
57 if ([request.method isEqualToString:@"facebook.fql.query"]) {
58 NSArray* users = result;
59 NSDictionary* user = [users objectAtIndex:0];
60 NSString* name = [user objectForKey:@"name"];
61 self.username = name;
62
63 if (self.post) {
64 [self postToWall];
65 self.post = NO;
66 }
67 }
68}
69
70- (void)postToWall {
71
72 FBStreamDialog *dialog = [[[FBStreamDialog alloc] init]
73 autorelease];
74 dialog.userMessagePrompt = @"Enter your message:";
75 dialog.attachment = [NSString
76 stringWithFormat:@"{\"name\":\"Facebook Connect for
77 iPhone\",\"href\":\"http://developers.facebook.com/
78 connect.phptab=iphone\",\"caption\":\"Caption\",
79 \"description\":\"Description\",\"media\":[{\"type\":
80 \"image\",\"src\":\"http://img40.yfrog.com/img40/
81 5914/iphoneconnectbtn.jpg\",\"href\":
82 \"http://developers.facebook.com/connect.php?
83 tab=iphone/\"}],\"properties\":{\"another link\":
84 {\"text\":\"Facebook home page\",\"href\":
86
87 [dialog show];
88
89}
90
91- (BOOL)textFieldShouldReturn:(UITextField *)textField
92{
93 [textField resignFirstResponder];
94 return YES;
95}
96
97@end

Define API key and Secret key with the keys you received while registering your app on facebook.

1#define _APP_KEY @"43e37a535cc09c2013bd76fde78dfcc7"
2#define _SECRET_KEY @"cc14801521a0c4d1dc31b7cacb891072"

Validate session variable in ViewDidLoad. If it doesn’t exist then create the same for using API key and Secret key. For that, one needs to conform the protocol FBSessionDelegate in respective header file. Also create a login button using FBLoginButton.

While implementing protocol FBSessionDelegate one needs to implement following mandatory method

1(void)session:(FBSession*)session didLogin:(FBUID)uid

This methos is automatically called when user is logged in using FBConnect SDK.
In this method we get session for that user and it’s uid which unique identifier for that user.

Once FBSession session is avaiable, we can accesss all the APIs provided by Facebook.
For now, we will see how to post user name and status on the facebook wall.

To get Facebook username a request is send in which select query is written to get username using uid.

1NSString* fql = [NSString stringWithFormat:
2@"select uid,name from user where uid == %lld", self.usersession.uid];
3NSDictionary* params = [NSDictionary dictionaryWithObject:fql forKey:@"query"];
4[[FBRequest requestWithDelegate:self] call:@"facebook.fql.query" params:params];

Override following FBRequestDelegate method to check the reponse of above query.

1(void)request:(FBRequest*)request didLoad:(id)result

The argument result is an array of NSDictionary Objects which contains info for that user as key-value pairs. Retrieve it as follows:

1NSArray* users = result;
2NSDictionary* user = [users objectAtIndex:0];
3NSString* name = [user objectForKey:@"name"];

Use FBStreamDialog class post message on the facbook wall. A dialog pops up with a message box to post on Wall.

1FBStreamDialog *dialog = [[[FBStreamDialog alloc] init] autorelease];
2dialog.userMessagePrompt = @"Enter your message:";
3dialog.attachment = [NSString stringWithFormat:@"{\"name\":\"Facebook Connect for iPhone\",\"href\":\"http://developers.facebook.com/connect.php?tab=iphone\",\"caption\":\"Caption\",\"description\":\"Description\",\"media\":[{\"type\":\"image\",\"src\":\"http://img40.yfrog.com/img40/5914/iphoneconnectbtn.jpg\",\"href\":\"http://developers.facebook.com/connect.php?tab=iphone/\"}],\"properties\":{\"another link\":{\"text\":\"Facebook home page\",\"href\":\"http://www.facebook.com\"}}}"];
4[dialog show];

Now Save project (Command +S). Build and Run Project.
Simulator will look like as follows

Click on Fconnect Button and Facebook Login Dialog will appear.

Login with your user name and Password . Wait for untill post to Wall Dialog pops up

The Msg on Facebook will something look like this

You can download the source code from here