Thursday 2 July 2009

[Cocoa] How to add a toolbar with button on top of a UITextView in order to add a dismiss button

The big problem with UITextView is there isn't any native way to hide the keyboard once the input ended.
The following code describes a DissmisableTextView. This view extends UITextView adding on top of the keyboard associated with this UITextView a toolbar with a "Done" Button :



Here is the code :
//
//  DismissableTextView.h
//  
//  A textView allowing to dismiss keyboard with a toolbar and a
//  Done button on top of the keyboard
//
//  Created by Vincent Demay on 02/07/09.
//

#import 


@interface DismissableTextView : UITextView {

	UIToolbar* keyboardToolbar;
}

- (void) keyboardWillShow:(NSNotification *)note;
- (void) dismissKeyboard;

@end



//
//  DismissableTextView.m
//  murena
//
//  Created by Vincent Demay on 02/07/09.
//

#import "DismissableTextView.h"


@implementation DismissableTextView


- (id)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
		//register a specific method on keyboard appearence
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
    }
    return self;
}



- (void)keyboardWillShow:(NSNotification *)notification 
{	
    for (UIWindow *keyboardWindow in [[UIApplication sharedApplication] windows]) {
		
        // Now iterating over each subview of the available windows
        for (UIView *keyboard in [keyboardWindow subviews]) {
			
            // Check to see if the description of the view we have referenced is UIKeyboard.
            // If so then we found the keyboard view that we were looking for.
            if([[keyboard description] hasPrefix:@"<UIKeyboard"] == YES) {
				NSValue *v = [[notification userInfo] valueForKey:UIKeyboardBoundsUserInfoKey];
				CGRect kbBounds = [v CGRectValue];
				
				if(keyboardToolbar == nil) {
					keyboardToolbar = [[UIToolbar alloc] initWithFrame:CGRectZero];
					keyboardToolbar.barStyle = UIBarStyleBlackTranslucent;
					
					UIBarButtonItem *barButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"Done" style:UIBarButtonItemStyleBordered target:self action:@selector(dismissKeyboard)];
					UIBarButtonItem *flex = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
					NSArray *items = [[NSArray alloc] initWithObjects:flex, barButtonItem, nil];
					[keyboardToolbar setItems:items];	
					[items release];	
				}				
				
				[keyboardToolbar removeFromSuperview];
				keyboardToolbar.frame = CGRectMake(0, 0, kbBounds.size.width, 30);
				[keyboard addSubview:keyboardToolbar];
				keyboard.bounds = CGRectMake(kbBounds.origin.x, kbBounds.origin.y, kbBounds.size.width, kbBounds.size.height + 60);
				
				for(UIView* subKeyboard in [keyboard subviews]) {
					if([[subKeyboard description] hasPrefix:@"<UIKeyboardImpl"] == YES) {
						subKeyboard.bounds = CGRectMake(kbBounds.origin.x, kbBounds.origin.y - 30, kbBounds.size.width, kbBounds.size.height);	
					}						
				}
            }
        }
    }
}

- (void) dismissKeyboard {
	[self resignFirstResponder];
}



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


@end

Tuesday 23 June 2009

Cocoa : Who to handle MouveXXX events on UIWebView

Default behavior of the UIWebView is : eat touchXXX events and not send them to the nextResponder. One way to be able to catch this kind of event on a UIWebView is to add on top of it a UIView. But at this point, links, scroll, etc... are not capture to inner components of the under UIWebView. Here is a HACK to make this struff work :
//
//  TouchUIWebView.h
//
//  Created by Vincent Demay on 19/06/09.
//  Copyright 2009 __MyCompanyName__. All rights reserved.
//

#import 

@interface DummyTapView : UIView {
	
	UIView * uiScroller_;
	UIView * uiWebDocumentView_;
}
@property(nonatomic, retain) UIView *uiScroller;
@property(nonatomic, retain) UIView *uiWebDocumentView;

@end


@interface TouchUIWebView : UIWebView {
}

@end

//
//  TouchUIWebView.m
//
//  Created by Vincent Demay on 19/06/09.
//  Copyright 2009 __MyCompanyName__. All rights reserved.
//

#import "TouchUIWebView.h"


const char* kUIScrollerName = "UIScroller";
const char* kUIWebDocumentView= "UIWebDocumentView";

@implementation DummyTapView

@synthesize uiScroller = uiScroller_;
@synthesize uiWebDocumentView = uiWebDocumentView_;

//
// retreive the scroller view in uiwebView
// used to compute scrolling in the loaded web page
//
- (UIView*) uiScroller {
	if( self.superview !=nil && uiScroller_ == nil ) {
		NSArray *views = [self.superview subviews];
		for( id view in views ) {
			const char* name = object_getClassName(view);
			if( !strncmp( name, kUIScrollerName, strlen(name) ) ) {
				uiScroller_ = view;
				return uiScroller_;
			}
		}
	}
	return uiScroller_;
}

//
// retreive the document view in UiWebView
// used to compute touch on link etc...
//
- (UIView*) uiWebDocumentView {
	if( self.superview != nil && uiWebDocumentView_ == nil ) {
		NSArray *views = [self.uiScroller subviews];
		for( id view in views ) {
			const char* name = object_getClassName(view);
			if( !strncmp( name, kUIWebDocumentView, strlen(name) ) ) {
				uiWebDocumentView_ = view;
				return uiWebDocumentView_;
			}
		}
	}
	return uiWebDocumentView_;
}

- (id) initWithFrame:(CGRect)frame {
	self = [super initWithFrame:frame];
	self.backgroundColor = [UIColor clearColor];
	return self;
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
	[self.uiScroller touchesBegan:touches withEvent:event];
	[self.uiWebDocumentView touchesBegan:touches withEvent:event];
	[self.nextResponder touchesBegan:touches withEvent:event];

}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
	[self.uiScroller touchesMoved:touches withEvent:event];
	[self.uiWebDocumentView touchesMoved:touches withEvent:event];
	[self.nextResponder touchesMoved:touches withEvent:event];

}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
	[self.uiScroller touchesEnded:touches withEvent:event];
	[self.uiWebDocumentView touchesEnded:touches withEvent:event];
	[self.superview didFinishGesturesInView:self.superview forEvent:event];
	[self.nextResponder touchesEnded:touches withEvent:event];

}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
	[self.uiScroller touchesCancelled:touches withEvent:event];
	[self.uiWebDocumentView touchesCancelled:touches withEvent:event];
	[self.nextResponder touchesCancelled:touches withEvent:event];

}
@end



@implementation TouchUIWebView

- (id)initWithFrame:(CGRect)frame
{
    if (self = [super initWithFrame:frame]) {
        // Initialization code	
		DummyTapView* view = [[DummyTapView alloc] 
							  initWithFrame:CGRectMake( 0,0,self.frame.size.width,self.frame.size.height)];
		[self addSubview:view];
		[view release];
    }
    return self;
	
}

@end

Wednesday 4 February 2009

Writing / Reading files on native Iphone Application

Here is a little sample to write/read files with objective c on native Iphone Application.
This snippet write into the Document Directory of the application. We will see later problems when trying to write in the Resources folder


WRITE
NSString *dataStr = @"my data";

//get Document Root
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];

//append file name to path	
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:@"myFile"];

//prepar data in A NSData from a String
NSData *aData = [dataStr dataUsingEncoding: NSUTF8StringEncoding];

//Write to the file.
//File will be automacally created if not exist
[aData writeToFile:filePath atomically:YES];



READ
//get Document root
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
	
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:@"myFile"];
NSString *myText = [NSString stringWithContentsOfFile:filePath]; 
if (myText) {
    return myText;
} else  {
    //can not read because file does not exists
    //make here your error handler 
}




WARNING : It is possible to get a file from Resources Folder with the follwing line :
NSString *filePath = [[NSBundle mainBundle] pathForResource:fileName ofType:extension];

Be carreful with that because if the file does not exist filePath will be null, so it will be impossible to create the file... difficult to write into the file :p

Sunday 11 January 2009

Sending HTTP request from Iphone App

How to send a HTTP request from Cocoa Application
        //prepar request
	NSString *urlString = [NSString stringWithFormat:@"http://urlToSend.com"];
	NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] init] autorelease];
	[request setURL:[NSURL URLWithString:urlString]];
	[request setHTTPMethod:@"POST"];
	
        //set headers
	NSString *contentType = [NSString stringWithFormat:@"text/xml"];
	[request addValue:contentType forHTTPHeaderField: @"Content-Type"];

	//create the body
	NSMutableData *postBody = [NSMutableData data];
	[postBody appendData:[[NSString stringWithFormat:@"<xml>"] dataUsingEncoding:NSUTF8StringEncoding]];
	[postBody appendData:[[NSString stringWithFormat:@"<yourcode/>"] dataUsingEncoding:NSUTF8StringEncoding]];
	[postBody appendData:[[NSString stringWithFormat:@"</xml>"] dataUsingEncoding:NSUTF8StringEncoding]];
	
        //post
	[request setHTTPBody:postBody];
	
	//get response
	NSHTTPURLResponse* urlResponse = nil;  
	NSError *error = [[NSError alloc] init];  
	NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&urlResponse error:&error];  
	NSString *result = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
	NSLog(@"Response Code: %d", [urlResponse statusCode]);
	if ([urlResponse statusCode] >= 200 && [urlResponse statusCode] < 300) {
		NSLog(@"Response: %@", result);
	        
                //here you get the response

	}

Friday 9 January 2009

Getting data from info.plist

How to get data from info.plist file in Iphone app development :
NSString * stringFromInfoPlist = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"stringInInfoPlist"];



Update : More info on *.plist files management here : iPhone Development Blog

Saturday 3 January 2009

Getting contacts from adress book

Here is a simple to way to access to Iphone address book for Cocoa Iphone developers :
// open the default address book.
ABAddressBookRef m_addressbook = ABAddressBookCreate();
if (!m_addressbook) { 
    NSLog(@"opening address book"); 
}

//get people and index
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(m_addressbook);
CFIndex nPeople = ABAddressBookGetPersonCount(m_addressbook);

//iterate on each person
for (int i=0;i < nPeople;i++) {
    ABRecordRef ref = CFArrayGetValueAtIndex(allPeople,i);

    //get phone numbers and names
    ABMultiValueRef phoneNumberProperty = ABRecordCopyValue(ref, kABPersonPhoneProperty);
    NSArray* phoneNumbers = (NSArray*)ABMultiValueCopyArrayOfAllValues(phoneNumberProperty);
    NSString* name = (NSString*)ABRecordCopyValue(ref, kABPersonFirstNameProperty);
    CFRelease(phoneNumberProperty);

    //Loop to display results
    NSLog(@"Name = %@", name);
    NSLog(@"Phone numbers = ");
    for (int j=0; j<[phoneNumbers count]; j++) { 
        NSLog(@" phone -> %@", [phoneNumbers objectAtIndex:j]); 
    }

    //release memory
    [phoneNumbers release];
}

Sunday 13 January 2008

Web 2.0 famous website becomes iphone compliant

The famous phone from Apple is now very famous and a lot ot people get one. So several social web2.0 website has developed a specific website for this new phone:


Official websites
Unofficial
If you know other Iphone specialized web social site, please let me know commenting this post.