15 January 2010
So you want to build an iPhone application and you would like it to have a chat facility with the style and
functionality of the iPhone’s SMS application but you don’t know where to start. This is not the perfect
tutorial on how to build the full application this is just a little bit of sample code and tech knowhow that
I came up with after the problems I have had with the multiple lines growing text input field.
I used two UIViews in my main view. The top view contains a UITableView and the bottom view contains a UITextview
and two UIButtons. Here is the complete code for my for header (.h) file
#import
@interface MultilineTextboxViewController : UIViewController {
IBOutlet UIView *viewTable;
IBOutlet UIView *viewForm;
IBOutlet UITextView *chatBox;
IBOutlet UIButton *chatButton;
}
@property (nonatomic, retain) UIView *viewTable;
@property (nonatomic, retain) UIView *viewForm;
@property (nonatomic, retain) UITextView *chatBox;
@property (nonatomic, retain) UIButton *chatButton;
- (IBAction)chatButtonClick:(id)sender;
@end
With that done and while we are setting everything up lets go and add our items to our main (.m) file at the same time not forgetting to de-allocate them as well.
@synthesize viewTable;
@synthesize viewForm;
@synthesize chatBox;
@synthesize chatButton;
- (void)dealloc{
[viewTable release];
[viewForm release];
[chatBox release];
[chatButton release];
[super dealloc];
}
In the (void)viewDidLoad method we need to add some notification observers so that we can see when the keyboard is shown or hidden and when the user presses a
key on the keyboard.
- (void)viewDidLoad {
//set notification for when keyboard shows/hides
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(keyboardWillHide:)
name:UIKeyboardWillHideNotification
object:nil];
//set notification for when a key is pressed.
[[NSNotificationCenter defaultCenter] addObserver:self
selector: @selector(keyPressed:)
name: UITextViewTextDidChangeNotification
object: nil];
//turn off scrolling and set the font details.
chatBox.scrollEnabled = NO;
chatBox.font = [UIFont fontWithName:@"Helvetica" size:14];
[super viewDidLoad];
}
When focus is set on the textview the keyboard will be shown. Because the textview and buttons are both in the lower viewForm on the screen,
the keyboard is going to ride up and go over these. So what we want to do is adjust the height of viewTable and the position of viewForm. We
do this in the following method.
-(void) keyboardWillShow:(NSNotification *)note{
// get keyboard size and loction
CGRect keyboardBounds;
[[note.userInfo valueForKey:UIKeyboardBoundsUserInfoKey] getValue: &keyboardBounds];
// get the height since this is the main value that we need.
NSInteger kbSizeH = keyboardBounds.size.height;
// get a rect for the table/main frame
CGRect tableFrame = viewTable.frame;
tableFrame.size.height -= kbSizeH;
// get a rect for the form frame
CGRect formFrame = viewForm.frame;
formFrame.origin.y -= kbSizeH;
// animations settings
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.3f];
// set views with new info
viewTable.frame = tableFrame;
viewForm.frame = formFrame;
// commit animations
[UIView commitAnimations];
}
Now that the keyboard is shown and our views have been adjusted we want to capture the text the user is entering and see if we need
to make any adjustments to the chatBox. Lucky for us we can use the CGSize object, pass it some text, and tell the object what size we
would want to constrain the text to and from that we can calculate get height.
Now this is where a little trial and error comes in. The line varies with the size of the font and your width of your CGSize object will
vary with the width of your UITextview so you will have to experiment a little. The value of 12 use in the code below is the difference
in height between the starting height of my chatBox and the line height based on the font that I have set.
-(void) keyPressed: (NSNotification*) notification{
// get the size of the text block so we can work our magic
CGSize newSize = [chatBox.text
sizeWithFont:[UIFont fontWithName:@"Helvetica" size:14]
constrainedToSize:CGSizeMake(222,9999)
lineBreakMode:UILineBreakModeWordWrap];
NSInteger newSizeH = newSize.height;
NSInteger newSizeW = newSize.width;
// I output the new dimensions to the console
// so we can see what is happening
NSLog(@"NEW SIZE : %d X %d", newSizeW, newSizeH);
if (chatBox.hasText)
{
// if the height of our new chatbox is
// below 90 we can set the height
if (newSizeH <= 90)
{
[chatBox scrollRectToVisible:CGRectMake(0,0,1,1) animated:NO];
// chatbox
CGRect chatBoxFrame = chatBox.frame;
NSInteger chatBoxH = chatBoxFrame.size.height;
NSInteger chatBoxW = chatBoxFrame.size.width;
NSLog(@"CHAT BOX SIZE : %d X %d", chatBoxW, chatBoxH);
chatBoxFrame.size.height = newSizeH + 12;
chatBox.frame = chatBoxFrame;
// form view
CGRect formFrame = viewForm.frame;
NSInteger viewFormH = formFrame.size.height;
NSLog(@"FORM VIEW HEIGHT : %d", viewFormH);
formFrame.size.height = 30 + newSizeH;
formFrame.origin.y = 199 - (newSizeH - 18);
viewForm.frame = formFrame;
// table view
CGRect tableFrame = viewTable.frame;
NSInteger viewTableH = tableFrame.size.height;
NSLog(@"TABLE VIEW HEIGHT : %d", viewTableH);
tableFrame.size.height = 199 - (newSizeH - 18);
viewTable.frame = tableFrame;
}
// if our new height is greater than 90
// sets not set the height or move things
// around and enable scrolling
if (newSizeH > 90)
{
chatBox.scrollEnabled = YES;
}
}
}
Once we are and the user presses the send button we want to do something with our text, the keyword will disappear and
we want to reset our view back as they were. So how do we do that?
- (IBAction)chatButtonClick:(id)sender{
// hide the keyboard, we are done with it.
[chatBox resignFirstResponder];
chatBox.text = nil;
// chatbox
CGRect chatBoxFrame = chatBox.frame;
chatBoxFrame.size.height = 30;
chatBox.frame = chatBoxFrame;
// form view
CGRect formFrame = viewForm.frame;
formFrame.size.height = 45;
formFrame.origin.y = 415;
viewForm.frame = formFrame;
// table view
CGRect tableFrame = viewTable.frame;
tableFrame.size.height = 415;
viewTable.frame = tableFrame;
}
The resignFirstResponder is going to hide the keyboard and then all we have to do is set the views and chatBox back to their original states.
-(void) keyboardWillHide:(NSNotification *)note{
// get keyboard size and loction
CGRect keyboardBounds;
[[note.userInfo valueForKey:UIKeyboardBoundsUserInfoKey] getValue: &keyboardBounds];
// get the height since this is the main value that we need.
NSInteger kbSizeH = keyboardBounds.size.height;
// get a rect for the table/main frame
CGRect tableFrame = viewTable.frame;
tableFrame.size.height += kbSizeH;
// get a rect for the form frame
CGRect formFrame = viewForm.frame;
formFrame.origin.y += kbSizeH;
// animations settings
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.3f];
// set views with new info
viewTable.frame = tableFrame;
viewForm.frame = formFrame;
// commit animations
[UIView commitAnimations];
}
And there you go, a textview that starts off as a single line and grows in size as the user enters text to a max size before becoming a scrolling textview.
If you have any comments or questions why not send me a message.
20 July 2008
To drill the holes for the fins, I made sure that my markings ran parallel with the boards centre and that the fins at each end where in a straight line. Using a 2mm
metal drill, I drilled the pilot holes. Working with fibreglass you are apparently meant to treat it as if working with metal (drills, sawing filling etc). Once the
holes were drilled it was time to sand the board.
I used a 240 grit sand paper and my orbital sander. A random orbital sander will give you a better finish. When sanding I used a dust mask and the vacuum attachment
on the sander to keep the fibreglass dust to a minimum and out of my lungs. Once the board was smooth I decided to give it a few coats of paint. Since this is my
prototype board and the first board I am making I am not going over the top and spending loads of cash on top notch quality paint. So standard body work paint was applied
if this works on cars it will be fine for my board.
Once I have my board tested and I am finally happy with future boards and their quality I shall invest in some good graphics. Once all painted and the paint had dried
it was off to the bath to wash it all down and to check if the board floats. I don't want to lose the board to the ocean on its first outing. While it was in the bath
I used this time to go over the board with a 600grit sand paper and really make the board nice and smooth. I sanded the board while it was underwater which took care of
all the fine dust issues.
Now the board was finally finished it was time to attach all the hardware. For my hardware I used Dakine Boost II deck pads with Dakine Control foot straps, a Slingshot
grab handle and Maui Magic Mystic fins to finish the board off. Now I just need to get out in the water and test the board out.
10 June 2008
So after a near miss over and the project still on track it was time to order another pack of resin having used all I had in the big mix. Now that I have got the new batch
of resin, this time I shall be mixing smaller batches.
After sanding the excess resin off the top of the core from the last time, it was time to do the top of the board. This time I was going to take my time and
do it slowly. First to go on was a good coat of resin and the first layer of fibreglass making sure that after it was wetted out it was tucked around all
the corners and followed the contours of the board. I did this for each layer until all three layers where laid out and wetted out.
Now the fibre glassing was complete, I covered the board with my peel-ply and then the breather layer and finally sealed the vacuum bag and started the
vacuum process. The vacuum process was left running for 12 hours. This was 4 hours longer than the last time but I was not going to get up at 2am so just left
it all running over night. The next morning I took the board out of the bag and trimmed the excess fibreglass using a Stanley knife.
To get a nice edge to my board I make a template of the board out of an old shelf that I had laying around. This would be a template for the router.
Looking back I should have made this template right from the start - shall remember this for board #2 Using a straight cutting bit in the router
I trimmed the board and this gave a nice sharp square edge to the board as well as trimming the fibreglass back to the ABS rails.
Now all that is left is to drill the holes for the fins, the holes in the top of the board so you can access the inserts, remove the wax from the
inserts (this was put there to stop resin going into the threads) and then sand and give it a few good coats of paint.