Some favorite site feeds aggregated locally: iPhone Development RSS   Adobe Labs RSS   Macrumors RSS

Friday, July 10, 2009

iPhone: Easy step through presentation application

Friday, July 10, 2009    2 Comments

This does not account for left and right swiping, but it could be added easily. Have a bunch of photos that you'd like to show someone in a presentation? Perhaps mock-ups of layouts, etc. This bit can really help you along. I wrote this quickly but it works pretty well, even with some subtle and nice effects. You'll need to create two custom buttons that you'll hook up to backImage and advanceImage.

The code reads JPG images that use "image_" in their filename. That allows you just load up your project with the files you want and they end up in the bundle, available to you. You could tweak this to use online assets too if you really wanted.

Enjoy on this fine Friday.
ClickViewController.m
#import "ClickThroughViewController.h"
#import <quartzcore/quartzcore.h>

@implementation ClickThroughViewController
@synthesize imageView, imageViewTop, aboutView, aboutButton, advanceButton, backButton, label;

- (void)updateLabel {
NSString *c = [[NSString alloc] initWithFormat:@"%i", count];
label.text = c;
[c release];
}

/*
You need to make sure the prototype images that you use are JPGs
and use the "image_" convention, otherwise the total count will
be off and your application will bork.
*/
- (void)viewDidLoad {
UIImage *img = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"image_1.jpg" ofType:nil]];
UIImage *img2 = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"image_6.jpg" ofType:nil]];
imageView.image = img2;
imageViewTop.image = img;
imageView.hidden = YES;
totalCount = 0;
aboutShowing = NO;

NSArray *d = [[NSBundle mainBundle] pathsForResourcesOfType:@"jpg" inDirectory:nil];
for(NSString *s in d){
if([[s lastPathComponent] hasPrefix:@"image_"]){
totalCount++;
}
}
count = 1;
prev = totalCount;
label.alpha = 0;
[self updateLabel];
[super viewDidLoad];
}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}

- (void)dealloc {
[imageView release];
[backButton release];
[advanceButton release];
[super dealloc];
}

// #pragma isn't very cool in my opinion, so...
//MARK: Custom Code

- (IBAction)advanceImage:(id)sender {
count++;
if( count > totalCount ){
count = 1;
}
if( count == 1 ){
prev = totalCount;
} else {
prev = count - 1;
}
[self updateLabel];

NSString *tmp = [[NSString alloc] initWithFormat:@"image_%i", count];
NSString *old = [[NSString alloc] initWithFormat:@"image_%i", prev];
UIImage *img = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:tmp ofType:@"jpg"]];
UIImage *img2 = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:old ofType:@"jpg"]];

imageView.image = img2;
imageViewTop.image = img;
label.alpha = 1;

CGContextRef context = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:[self imageViewTop] cache:YES];
[UIView setAnimationDuration:0.5];
[UIView commitAnimations];

CGContextRef context2 = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context2];
[UIView setAnimationDuration:1.0];
label.alpha = 0;
[UIView commitAnimations];
}

- (IBAction)aboutChange:(id)sender {
if( !aboutShowing ){
aboutShowing = YES;
aboutView.hidden = NO;
aboutView.frame = CGRectMake(0, -50, 320, 480);
aboutView.alpha = 0.0;
CGContextRef context = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context];
[UIView setAnimationDuration:1.0];
aboutView.frame = CGRectMake(0, 0, 320, 480);
aboutView.alpha = 1.0;
[UIView commitAnimations];

} else {
aboutShowing = NO;
CGContextRef context2 = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context2];
[UIView setAnimationDuration:1.0];
aboutView.frame = CGRectMake(0, -50, 320, 480);
aboutView.alpha = 0.0;
[UIView commitAnimations];
}
}

- (IBAction)backImage:(id)sender {
count--;
if( count < 1 ){
count = totalCount;
}
if( count == 1 ){
prev = totalCount;
} else {
prev = count + 1;
}
[self updateLabel];
NSString *tmp = [[NSString alloc] initWithFormat:@"image_%i", count];
NSString *old = [[NSString alloc] initWithFormat:@"image_%i", prev];
UIImage *img = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:tmp ofType:@"jpg"]];
UIImage *img2 = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:old ofType:@"jpg"]];
imageView.image = img2;
imageViewTop.image = img;
label.alpha = 1;

CGContextRef context = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:[self imageViewTop] cache:YES];
[UIView setAnimationDuration:0.5];
[UIView commitAnimations];

CGContextRef context2 = UIGraphicsGetCurrentContext();
[UIView beginAnimations:nil context:context2];
[UIView setAnimationDuration:1.0];
label.alpha = 0;
[UIView commitAnimations];
}

@end

Labels: , ,

 

Monday, June 29, 2009

How you target 2.x with the 3.0 SDK...

Monday, June 29, 2009    0 Comments

If you are using the 3.0 iPhone SDK, you'll notice that by default Xcode only shows you 3.0 as a target (Simulator and device). Before you were able to target all the SDKs you had installed. I personally don't worry about this default behavior, but when you're building an iPhone application, you may want to target previous SDKs.

I read about this online someplace, and this will get 2.x available again.

  1. Select your project file and Get Info.
  2. Under the General tab, you'll see a drop down for Base SDK for All Configurations and choose your SDK there.
  3. You're done. You'll see all the SDKs listed now in the normal drop down you're used to using.

Labels:

 

Thursday, May 28, 2009

Xcode: Uncaught exceptions with breakpoint!

Thursday, May 28, 2009    2 Comments

While developing for the Mac or the iPhone, you're going to bump heads with the TERMINATING_DUE_TO_UNCAUGHT_EXCEPTION a bit. While this is nominally useful information, you never are told where the exception happened, only the reason that it did. If your application isn't very large in scope, this may be all the information you'll need to debug the problem. However, for larger applications this isn't the best.

One thing I just discovered is that you can have Xcode automagically place a breakpoint where the exception occurs, thus showing you just where the exception was thrown. Paired with the information on why, this is a big help in debugging.

To set this up, open up your Breakpoints window (in my version of Xcode I double-click on the Breakpoints items in the editor window Groups & Files tree control. You'll see a breakpoint item "Double-Click for Symbol" - set the breakpoint to "objc_exception_throw" and you're done. It should look something like this:
Now when you get an exception, you should be able to click the exposed line in the debugger stack trace which will take you to the offending line of code in your project.

Labels: , ,

 

Wednesday, May 6, 2009

Getting columned data in a UITableView

Wednesday, May 6, 2009    0 Comments

Since I'm still fairly green to this whole Objective-C thing and I am still learning the APIs that are available (there are a billion of them), I don't always know how to do exactly what I want to do. A case in point... I wanted to present a high scores screen in a little game I am coding up (a learning exercise... I highly recommend coding a game to expose yourself to tons of little challenges).

I have an NSMutableArray that I have stuffed with NSDictionary items. Each of those has a key for name and score. Easy. However I thought about using the "\t" character like we can do in ActionScript 3 and implement a tabStop somehow... thus negating the need to use dictionaries at all and just munge the name with the score.

Obviously this makes sorting an extremely stupid activity (many hoops to needlessly jump through). So it's not a solution by any means (an array of dictionaries is), but I wanted to see how I might replicate the functionality of tabStops in Objective-C (non-paragraph).

I have yet to find the solution. However in beating myself up in trying to figure out how to properly implement NSTextTab for a non UITextField I came across a true solution. Adding subviews!

This is exactly what I was after, and it has the benefit of allowing tons of flexibility in how to best present your textual data in the UITableView.

Without dressing the main method up too much, I think you'll be able to see what's going on here. I am only using a straight NSArray for this example, but you can see how this works.
// Set up the table view cells
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *SimpleTableIdentifier = @"SimpleTableIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SimpleTableIdentifier];

UILabel *label; // for scores
UILabel *nameLabel;

if( cell == nil ){

CGRect frame = CGRectMake(0,0,300,44);
cell = [[[UITableViewCell alloc] initWithFrame:frame reuseIdentifier:SimpleTableIdentifier] autorelease];
cell.selectionStyle = UITableViewCellSelectionStyleNone;

//Create the score label in the cell
label = [[[UILabel alloc] initWithFrame:CGRectMake(0.0, 10.0, 70.0, 25.0)] autorelease];
label.tag = 1;
label.font = [UIFont boldSystemFontOfSize:18.0];//systemFontOfSize
label.textAlignment = UITextAlignmentRight;
label.backgroundColor = [UIColor clearColor];
label.textColor = [UIColor whiteColor];
label.autoresizingMask = UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleHeight;
[cell.contentView addSubview:label];
label.text = @"1000";

// Create the name label in the cell
nameLabel = [[[UILabel alloc] initWithFrame:CGRectMake(80.0, 10.0, 195.0, 25.0)] autorelease];
nameLabel.tag = 2;
nameLabel.font = [UIFont boldSystemFontOfSize:18.0];
nameLabel.textColor = [UIColor whiteColor];
nameLabel.backgroundColor = [UIColor clearColor];
nameLabel.lineBreakMode = UILineBreakModeWordWrap;
nameLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[cell.contentView addSubview:nameLabel];

} else {
// Out of view items
label = (UILabel *)[cell.contentView viewWithTag:1];
nameLabel = (UILabel *)[cell.contentView viewWithTag:2];
}

NSInteger row = [indexPath row];
nameLabel.text = [listData objectAtIndex:row];
cell.selected = NO;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}

Labels: , , , ,

 

Thursday, April 16, 2009

Sending an email from an iPhone application

Thursday, April 16, 2009    2 Comments

This certainly is not the most secure way of sending an email by any means, but it does work. So you would like your iPhone application to be able to send an email - perhaps a feedback form of some kind, etc. The example supplied here contains a UITextField and a UIButton. A UIAlertView and a UIActionSheet are also used. Oh, and there is a little snippet of PHP to put on your server someplace (that's the unsecure part here).

Your .h file:
#import <UIKit/UIKit.h>

@interface SendEmailViewController : UIViewController {
IBOutlet UIButton *button;
IBOutlet UITextField *messageText;
IBOutlet UIButton *backgroundButton;
}

@property (nonatomic, retain) UIButton *button;
@property (nonatomic, retain) UITextField *messageText;
@property (nonatomic, retain) UIButton *backgroundButton;

-(IBAction)sendMail:(id)sender;
-(IBAction)textFieldDoneEditing:(id)sender;
-(IBAction)backgroundClick:(id)sender;

@end
And now your .m file:
#import "SendEmailViewController.h"

@implementation SendEmailViewController

@synthesize button, messageText, backgroundButton;

-(IBAction)textFieldDoneEditing:(id)sender {
[sender resignFirstResponder];
}

-(IBAction)backgroundClick:(id)sender {
[messageText resignFirstResponder];
}

-(void)displayAlert {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Email Sent" message:@"Thank you for contacting me" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[messageText setText:@""];
[alert show];
[alert release];
}

-(void)displaySheet {
NSString *msg = nil;
msg = [[NSString alloc] initWithFormat:@"Send Email? Your message:\"%@\"", messageText.text];
UIActionSheet *actionSheet = [[UIActionSheet alloc] initWithTitle:msg delegate:self cancelButtonTitle:@"Not yet" destructiveButtonTitle:@"Yes" otherButtonTitles:nil];
[actionSheet showInView:self.view];
[actionSheet release];
[msg release];
}

-(void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex {
if( !(buttonIndex == [actionSheet cancelButtonIndex]) ){
NSString *post = nil;
post = [[NSString alloc] initWithFormat:@"message=%@",messageText.text];
NSData *postData = [post dataUsingEncoding:NSASCIIStringEncoding allowLossyConversion:YES];
NSString *postLength = [NSString stringWithFormat:@"%d", [postData length]];
NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
[request setURL:[NSURL URLWithString:@"http://www.yourserveraddy/yourScript.php"]];
[request setHTTPMethod:@"POST"];
[request setValue:postLength forHTTPHeaderField:@"Content-Length"];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
[request setHTTPBody:postData];
[ NSURLConnection connectionWithRequest:request delegate:self ];

[post release];
[self displayAlert];
}
}

-(IBAction)sendMail:(id)sender {
[self displaySheet];
}

- (void)didReceiveMemoryWarning {
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];

// Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
[button release];
[messageText release];
[backgroundButton release];
}
And lastly your PHP file:
<?php
$message = $_REQUEST['message'] ;
mail( "recipient@server.com", "Test Message", $message );
?>
You just need to set your outlets and set you should be all set.

Labels: , ,

 

Monday, April 13, 2009

Custom buttons for your Objective-C applications

Monday, April 13, 2009    0 Comments

You have a few choices (that I know of right now) for making custom versions of your buttons for an Objective-C project in InterfaceBuilder (iPhone). You can turn your UIButton into a custom type, and use a background image... however you're locked into making the background match the size of your button.

In Flash the option of using a Scale-9 approach is available and it's here for Objective-C too. This method will allow you to make very small base graphics to serve as your button background and it will resize properly. The only drawback is that you'll need to register each button to affect it. The other option would be to subclass UIButton and then make sure you use it instead. I haven't had the need to do that, nor have I even really tried that.

To see the Obj-C skinning in action, here is the code I am using from a test project that I have (you can see what happens as well):

- (void)viewDidLoad {
UIImage *buttonImageNormal = [UIImage imageNamed:@"whiteButton.png"];
UIImage *stretchableButtonImageNormal = [buttonImageNormal stretchableImageWithLeftCapWidth:12 topCapHeight:10];
[button1 setBackgroundImage:stretchableButtonImageNormal forState:UIControlStateNormal];
[button2 setBackgroundImage:stretchableButtonImageNormal forState:UIControlStateNormal];
[button3 setBackgroundImage:stretchableButtonImageNormal forState:UIControlStateNormal];
[button4 setBackgroundImage:stretchableButtonImageNormal forState:UIControlStateNormal];
[button5 setBackgroundImage:stretchableButtonImageNormal forState:UIControlStateNormal];
[button6 setBackgroundImage:stretchableButtonImageNormal forState:UIControlStateNormal];

UIImage *buttonImagePressed = [UIImage imageNamed:@"blueButton.png"];
UIImage *stretchableButtonImagePressed = [buttonImagePressed stretchableImageWithLeftCapWidth:12 topCapHeight:10];
[button1 setBackgroundImage:stretchableButtonImagePressed forState:UIControlStateHighlighted];
[button2 setBackgroundImage:stretchableButtonImagePressed forState:UIControlStateHighlighted];
[button3 setBackgroundImage:stretchableButtonImagePressed forState:UIControlStateHighlighted];
[button4 setBackgroundImage:stretchableButtonImagePressed forState:UIControlStateHighlighted];
[button5 setBackgroundImage:stretchableButtonImagePressed forState:UIControlStateHighlighted];
[button6 setBackgroundImage:stretchableButtonImagePressed forState:UIControlStateHighlighted];
[super viewDidLoad];
}

Labels: ,

 

Thursday, April 2, 2009

A big difference between Objective-C and AS3

Thursday, April 2, 2009    4 Comments

Objective-C. String comparisons from text controls and normal strings. It's something you just take for granted in AS3.

myText_txt.text = "Hello";
if( myText_txt.text == "Hello" ){ trace("There");}
Easy enough on that string comparison. I thought it would be the same for Objective-C and it isn't. I felt like an idiot for a while today as I struggled with that logic above.

I had a method being called by a UITextField in an iPhone application whenever the value of the field changed.

-(IBAction)editing:(id)sender {
if( field1.text == @"" ){
button.hidden = YES;
} else {
button.hidden = NO;
}
NSLog( @"%@", field1.text );
}
That seems simple enough but it never worked as intended. It's comparing pointers instead of String values. The code below (if it were not for Google, I would have never stumbled upon this myself) does what I wanted.

-(IBAction)editing:(id)sender {
if ([field1.text length] && [field1.text compare:@"Eric"
options:NSLiteralSearch
range:NSMakeRange(0,4)] == NSOrderedSame){
button.hidden = NO;
} else {
button.hidden = YES;
}
}
So what's happening here? We check for a string length to make sure that the compare doesn't blow up with an out of range error. This is essentially the same thing as checking for "" in AS3: if( field1.text != "")... And then there is that compare. I never would have found that myself. The options show how you can check a certain number of characters into the string... and here I should check to make sure the length >= to that range, but I'm not. I should add that.

Anyway, I hope this helps someone save time in their day.

Labels:

 

Wednesday, April 1, 2009

Xcode: get alphabetized methods all the time

Wednesday, April 1, 2009    0 Comments

After a bit of chatter with an Apple forum administrator, I found a way to get Xcode to do what I want in regards to it's method popup menu.

Quick overview:
I like using TextMate on the Mac for ActionScript 3 coding (it's not FlashDevelop, but it's pretty good). The method popup menu for methods is always alphabetized. Personally, I like this a lot. In FlashDevelop you can view all your methods but it's listed in the order they exist in the class file.

While using Xcode, the method popup menu can be affected by using #pragma mark to a nice effect, however the list of methods by default is in the order they exist in the class file.

After some conversation, I was informed that holding the option key down before clicking on that method menu will alphabetize the list. That's cool, but what if you don't want to remember to use the modifier key all of the time?

In the Terminal, enter this:
$ defaults write com.apple.Xcode PBXSortMethodsPopup -bool YES

Now by default that menu will be alphabetized and holding down the option key prior to selection will show you in file order. Awesome. I don't know what this does for your pragma marks, I'll have to check that tomorrow. Update: It actually ignores all set pragma marks (for now anyway).


Above: this is what you should by default after you run the Terminal command above. Remember to restart Xcode. Now, when you Option-click that menu after you'll see this:



One thing that doesn't happen is alphabetizing within pragma mark blocks themselves, although Apple has already looked into this. It would be a subtle yet nice addition to the tool.

Labels: