Long Press: BAD_EXC_ACCESS - objective-c

Here is my code:
#interface UserProfileViewController : UIViewController<UIGestureRecognizerDelegate>{
}
#property (nonatomic, retain) UILabel *myLabel;
#property (nonatomic, retain) UIImageView *imageView;
#end
#implementation UserProfileViewController
#synthesize myLabel;
#synthesize imageView;
- (void)viewDidLoad
{
[super viewDidLoad];
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
scrollView.contentSize = CGSizeMake(320, 700);
scrollView.clipsToBounds = YES;
[scrollView setUserInteractionEnabled:YES];
myLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 40)];
myLabel.text = #"Kim Gysen";
myLabel.center = CGPointMake(CGRectGetWidth(self.view.bounds)/2.0f, 25);
myLabel.textAlignment = NSTextAlignmentCenter;
myLabel.textColor = [UIColor whiteColor];
[myLabel setBackgroundColor:[UIColor clearColor]];
self.imageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 140, 180)];
self.imageView.center = CGPointMake(CGRectGetWidth(self.view.bounds)/2.0f, 150);
UIImage *image = [UIImage imageNamed: #"ProfilePic.jpeg"];
[imageView setImage:image];
//Long press
self.imageView.userInteractionEnabled = YES;
UILongPressGestureRecognizer *longPressGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(handleLongPressFrom:)];
longPressGestureRecognizer.delegate = self;
[self.imageView addGestureRecognizer:longPressGestureRecognizer];
[scrollView addSubview:myLabel];
[scrollView addSubview:imageView];
[self.view addSubview:scrollView];
}
- (void) handleLongPressFrom: (UISwipeGestureRecognizer *)recognizer
{
CGPoint location = [recognizer locationInView:self.view];
NSLog(#"Tap Gesture Coordinates: %.2f %.2f", location.x, location.y);
if(UIGestureRecognizerStateBegan == recognizer.state)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Gesture Recognizer Demo"
message:#"Long Press Gesture performed"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil, nil];
[alert show];
}
}
I get no errors in my ViewDidLoad, but the BAD_EXC_ACCESS error appears on the long press, before the method is actually fired. I understood that I'm leaking somewhere but where?
I'm using ARC...

You should make a property in your main view controller (typed strong) that points to the ProfileViewController then use:
self.profileView = [[UserProfileViewController alloc] init];
[self.view addSubview: self.profileView.view];

Related

how to update the content in the UIlabel

When I use swipe gesture on the screen the label on the screen it didn't update the content and the number stop at 120, after I declare:
#property (weak, nonatomic) UILabel *label;
when I swipe the screen then it appear error on the Xcode,
If someone can help me to solve this problem I will really appreciate it
#interface ViewController ()
{
double numOfSpeed;
}
#property (weak, nonatomic) UILabel *label;
#end
implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
numOfSpeed = 120;
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(200, 300, 100, 100)];
label.text =[NSString stringWithFormat:#"%.0f", numOfSpeed];
label.backgroundColor = UIColor.blueColor;
[self.view addSubview:label];
UISwipeGestureRecognizer *swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeToControlTheSpeedOfRhythm:)];
UISwipeGestureRecognizer *swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeToControlTheSpeedOfRhythm:)];
UISwipeGestureRecognizer *swipeUp = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeToControlTheSpeedOfRhythm:)];
UISwipeGestureRecognizer *swipeDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:#selector(swipeToControlTheSpeedOfRhythm:)];
[swipeRight setDirection:UISwipeGestureRecognizerDirectionRight];
[swipeLeft setDirection:UISwipeGestureRecognizerDirectionLeft];
[swipeUp setDirection:UISwipeGestureRecognizerDirectionUp];
[swipeDown setDirection:UISwipeGestureRecognizerDirectionDown];
[swipeLeft setNumberOfTouchesRequired:1];
[swipeRight setNumberOfTouchesRequired:1];
[swipeUp setNumberOfTouchesRequired:1];
[swipeDown setNumberOfTouchesRequired:1];
[self.view addGestureRecognizer:swipeLeft];
[self.view addGestureRecognizer:swipeUp];
[self.view addGestureRecognizer:swipeDown];
[self.view addGestureRecognizer:swipeRight];
}
- (void)swipeToControlTheSpeedOfRhythm:(UISwipeGestureRecognizer *)sender
{
NSLog(#"gesture respone");
if(sender.direction == UISwipeGestureRecognizerDirectionLeft)
{
numOfSpeed -= 10;
self.label.text = [NSString stringWithFormat:#"%.0f", numOfSpeed];
NSLog(#"gesture Left respone");
}else if (sender.direction == UISwipeGestureRecognizerDirectionDown){
numOfSpeed -= 10;
self.label.text = [NSString stringWithFormat:#"%.0f", numOfSpeed];
NSLog(#"gesture down respone");
}else if (sender.direction==UISwipeGestureRecognizerDirectionUp){
numOfSpeed += 10;
self.label.text = [NSString stringWithFormat:#"%.0f", numOfSpeed];
NSLog(#"gesture up respone");
}else if(sender.direction==UISwipeGestureRecognizerDirectionRight){
numOfSpeed += 10;
self.label.text = [NSString stringWithFormat:#"%.0f", numOfSpeed];
NSLog(#"gesture right respone");
}
}
#end
You should init your UILabel like this:
self.label = [[UILabel alloc] initWithFrame:CGRectMake(200, 300, 100, 100)];
Then use self.label through all your code. The problem is that your label property is not being assigned inside your viewDidLoad code.
Edit
And use a strong reference in your UILabel property unless you're using #IBOutlets.
Remove "UILabel *" from
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(200, 300, 100, 100)];

UIView Animation Block Not Doing Anything

I have a very small animation I want to do by moving a view's frame using blocks (rather than the animation headers).
My view hierarchy is quite big so I will explain everything in regards of the specific view I want to animate.
The biggest view is the one that takes the whole screen, so it is 320x480 points. Inside this view, I have another view called "keypadContainerView" that is 320x200 points, located on 0, 261 and it appears at the bottom of the screen. This keypadContainerView has a subview called keypadView, which has a bunch of small buttons as subviews.
Biggest View -> KeypadContainerView -> keypadView -> UIbuttons.
An screenshot:
Although this could go without saying, the keypad there is the keypadContainerView, with is't keypadView and buttons. I need this hierarchy because I'm aiming for eye candy here, and each layer has a different background.
The way I create and deal with that view is here:
keypadViewContainer = [[[UIView alloc] initWithFrame:CGRectMake(0, 261, 320, 200)] autorelease]; //(Original is 0, 261, 320, 200)
keypadView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 200)];
[keypadViewContainer addSubview:keypadView];
//Add the buttons
[self.view addSubview:keypadViewContainer];
And this is how I'm trying to animate it:
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[UIView animateWithDuration:5.0 animations:^{
self.keypadViewContainer.frame = CGRectMake(0, 0, 320, 200);
} completion:NULL];
}
What is funny is that if I NSLog something in the animations: parameter, I actually get some output so the method is definitely getting called. It's just not animating anything at all.
The whole controller code is here, in case you need it:
//UnlockKeyboardViewController
//------------------------------------------------------------------------
#interface UnlockKeyboardViewController : UIViewController
{
NSArray *buttons;
NSArray *passcodeFields;
UIImage *buttonBackgroundImage;
UIImage *buttonBackgroundHighlightedImage;
UIImage *middleButtonBackgroundImage;
UIImage *middleButtonBackgroundImageHighlighted;
UIImage *screenBackgroundImage;
UIImage *infoViewContainerImage;
UIImage *keypadViewContainerImage;
UIImage *passcodeFieldsContainerImage;
UIImage *infoViewImage;
UIImage *passcodeViewImage;
UIView *infoViewContainer;
UIView *keypadViewContainer;
UIView *passcodeFieldsContainer;
UIView *infoView;
UIView *keypadView;
UIView *passcodeFieldsView;
UIView *infoToDisplayView; //The view the programmer passes to show in infoView.
}
#property(nonatomic, retain)UIImage *buttonBackgroundImage;
#property(nonatomic, retain)UIImage *buttonBackgroundHighlightedImage;
#property(nonatomic, retain)UIImage *screenBackgroundImage;
#property(nonatomic, retain)UIImage *keypadViewBackgroundImage;
#property(nonatomic, retain)UIImage *infoViewContainerImage;
#property(nonatomic, retain)UIImage *keypadViewContainerImage;
#property(nonatomic, retain)UIImage *passcodeFieldsContainerImage;
#property(nonatomic, retain)UIImage *infoViewImage;
#property(nonatomic, retain)UIImage *passcodeViewImage;
#property(nonatomic, retain)UIView *infoToDisplayView;
//Properties for container views.
#property(nonatomic, retain)UIView *infoViewContainer;
#property(nonatomic, retain)UIView *keypadViewContainer;
#property(nonatomic, retain)UIView *passcodeFieldsContainer;
#end
#implementation UnlockKeyboardViewController
#synthesize buttonBackgroundImage = _buttonBackgroundImage;
#synthesize buttonBackgroundHighlightedImage = _buttonBackgroundHighlightedImage;
#synthesize screenBackgroundImage = _screenBackgroundImage;
#synthesize keypadViewBackgroundImage = _keypadViewBackgroundImage;
#synthesize infoViewContainerImage = _infoViewContainerImage;
#synthesize keypadViewContainerImage = _keypadViewContainerImage;
#synthesize passcodeFieldsContainerImage = _passcodeFieldsContainerImage;
#synthesize infoViewImage = _infoViewImage;
#synthesize passcodeViewImage = _passcodeViewImage;
#synthesize infoToDisplayView = _infoToDisplayView;
//Synthesizers for container views.
#synthesize infoViewContainer = _infoViewContainer;
#synthesize keypadViewContainer = _keypadViewContainer;
#synthesize passcodeFieldsContainer = _passcodeFieldsContainer;
-(void)loadView
{
[super loadView];
self.view.frame = CGRectMake(0, 0, 320, 480);
_unlockKeyboardBundle = [NSBundle bundleForClass:[self class]];
buttonBackgroundImage = [UIImage imageWithContentsOfFile:[_unlockKeyboardBundle pathForResource:#"button" ofType:#"png"]];
middleButtonBackgroundImage = [UIImage imageWithContentsOfFile:[_unlockKeyboardBundle pathForResource:#"middleButton" ofType:#"png"]];
buttonBackgroundHighlightedImage = [UIImage imageWithContentsOfFile:[_unlockKeyboardBundle pathForResource:#"pushedButton" ofType:#"png"]];
middleButtonBackgroundImageHighlighted = [UIImage imageWithContentsOfFile:[_unlockKeyboardBundle pathForResource:#"pushedButtonMiddle" ofType:#"png"]];
infoViewContainerImage = [UIImage imageWithContentsOfFile:[_unlockKeyboardBundle pathForResource:#"infoViewContainerImage" ofType:#"png"]];
keypadViewContainerImage = [UIImage imageWithContentsOfFile:[_unlockKeyboardBundle pathForResource:#"keypadViewContainerImage" ofType:#"png"]];
passcodeFieldsContainerImage = [UIImage imageWithContentsOfFile:[_unlockKeyboardBundle pathForResource:#"passcodeViewContainerImage" ofType:#"png"]];
infoViewImage = [UIImage imageWithContentsOfFile:[_unlockKeyboardBundle pathForResource:#"infobackground" ofType:#"png"]];
passcodeViewImage = [UIImage imageWithContentsOfFile:[_unlockKeyboardBundle pathForResource:#"passcodescreen" ofType:#"png"]];
//self.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageWithContentsOfFile:[_unlockKeyboardBundle pathForResource:#"lockbackground" ofType:#"png"]]];
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
keypadViewContainer = [[[UIView alloc] initWithFrame:CGRectMake(0, 261, 320, 200)] autorelease]; //(Original is 0, 261, 320, 200)
keypadView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 200)];
[keypadViewContainer addSubview:keypadView];
keypadViewContainer.backgroundColor = [UIColor colorWithPatternImage:keypadViewContainerImage];
NSMutableArray *tempButtons = [NSMutableArray array];
self.view.opaque = YES;
UIButton *button1 = [UIButton buttonWithType:UIButtonTypeCustom];
[button1 setTitle:#"1" forState:UIControlStateNormal];
button1.frame = CGRectMake(0, 0, 106, 50);
UIButton *button4 = [UIButton buttonWithType:UIButtonTypeCustom];
[button4 setTitle:#"4" forState:UIControlStateNormal];
button4.frame = CGRectMake(0, 50, 106, 50);
UIButton *button7 = [UIButton buttonWithType:UIButtonTypeCustom];
[button7 setTitle:#"7" forState:UIControlStateNormal];
button7.frame = CGRectMake(0, 100, 106, 50);
UIButton *cancel = [UIButton buttonWithType:UIButtonTypeCustom];
[cancel setTitle:NSLocalizedString(#"cancel", #"Cancel string") forState:UIControlStateNormal];
cancel.frame = CGRectMake(0, 150, 106, 50);
UIButton *button2 = [UIButton buttonWithType:UIButtonTypeCustom];
[button2 setTitle:#"2" forState:UIControlStateNormal];
button2.frame = CGRectMake(106, 0, 108, 50);
UIButton *button5 = [UIButton buttonWithType:UIButtonTypeCustom];
[button5 setTitle:#"5" forState:UIControlStateNormal];
button5.frame = CGRectMake(106, 50, 108, 50);
UIButton *button8 = [UIButton buttonWithType:UIButtonTypeCustom];
[button8 setTitle:#"8" forState:UIControlStateNormal];
button8.frame = CGRectMake(106, 100, 108, 50);
UIButton *button0 = [UIButton buttonWithType:UIButtonTypeCustom];
[button0 setTitle:#"0" forState:UIControlStateNormal];
button0.frame = CGRectMake(106, 150, 108, 50);
UIButton *button3 = [UIButton buttonWithType:UIButtonTypeCustom];
[button3 setTitle:#"3" forState:UIControlStateNormal];
button3.frame = CGRectMake(214, 0, 106, 50);
UIButton *button6 = [UIButton buttonWithType:UIButtonTypeCustom];
[button6 setTitle:#"6" forState:UIControlStateNormal];
button6.frame = CGRectMake(214, 50, 106, 50);
UIButton *button9 = [UIButton buttonWithType:UIButtonTypeCustom];
[button9 setTitle:#"9" forState:UIControlStateNormal];
button9.frame = CGRectMake(214, 100, 106, 50);
UIButton *cancelOrDelete = [UIButton buttonWithType:UIButtonTypeCustom];
[cancelOrDelete setTitle:#"<-" forState:UIControlStateNormal];
cancelOrDelete.frame = CGRectMake(214, 150, 108, 50);
[tempButtons addObject:button1];
[tempButtons addObject:button2];
[tempButtons addObject:button3];
[tempButtons addObject:button4];
[tempButtons addObject:button5];
[tempButtons addObject:button6];
[tempButtons addObject:button7];
[tempButtons addObject:button8];
[tempButtons addObject:button9];
[tempButtons addObject:button0];
[tempButtons addObject:cancel];
[tempButtons addObject:cancelOrDelete];
buttons = [[NSArray arrayWithArray:tempButtons] retain];
for(UIButton *theButton in buttons)
{
if([theButton.currentTitle isEqualToString:#"2"] || [theButton.currentTitle isEqualToString:#"5"] || [theButton.currentTitle isEqualToString:#"8"] || [theButton.currentTitle isEqualToString:#"0"])
{
[theButton setBackgroundImage:middleButtonBackgroundImage forState:UIControlStateNormal];
[theButton setBackgroundImage:middleButtonBackgroundImageHighlighted forState:UIControlStateHighlighted];
}else
{
[theButton setBackgroundImage:buttonBackgroundImage forState:UIControlStateNormal];
[theButton setBackgroundImage:middleButtonBackgroundImageHighlighted forState:UIControlStateHighlighted];
}
[keypadView addSubview:theButton];
}
[self.view addSubview:keypadViewContainer];
passcodeFieldsView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0,320, 110)] autorelease];
passcodeFieldsContainer = [[[UIView alloc] initWithFrame:CGRectMake(0, 151, 320, 110)] autorelease];
passcodeFieldsContainer.backgroundColor = [UIColor colorWithPatternImage:passcodeFieldsContainerImage];
passcodeFieldsView.backgroundColor = [UIColor colorWithPatternImage:passcodeViewImage];
NSMutableArray *passTemps = [NSMutableArray array];
UITextField *tf1 = [[[UITextField alloc] initWithFrame:CGRectMake(24, 27, 50, 50)] autorelease];
UITextField *tf2 = [[[UITextField alloc] initWithFrame:CGRectMake(98, 27, 50, 50)] autorelease];
UITextField *tf3 = [[[UITextField alloc] initWithFrame:CGRectMake(172, 27, 50, 50)] autorelease];
UITextField *tf4 = [[[UITextField alloc] initWithFrame:CGRectMake(246, 27, 50, 50)] autorelease];
[passTemps addObject:tf1];
[passTemps addObject:tf2];
[passTemps addObject:tf3];
[passTemps addObject:tf4];
passcodeFields = [[NSArray arrayWithArray:passTemps] retain];
for(UITextField *theTf in passcodeFields)
{
theTf.borderStyle = UITextBorderStyleBezel;
theTf.backgroundColor = [UIColor whiteColor];
theTf.enabled = NO;
theTf.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
theTf.textAlignment = UITextAlignmentCenter;
theTf.adjustsFontSizeToFitWidth = YES;
theTf.alpha = 0.7;
theTf.secureTextEntry = YES;
[passcodeFieldsView addSubview:theTf];
}
[passcodeFieldsContainer addSubview:passcodeFieldsView];
[self.view addSubview:passcodeFieldsContainer];
infoView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 151)] autorelease];
infoView.backgroundColor = [UIColor colorWithPatternImage:infoViewImage];
infoViewContainer = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 151)] autorelease];
infoViewContainer.backgroundColor = [UIColor colorWithPatternImage:infoViewContainerImage];
[infoViewContainer addSubview:infoView];
[self.view addSubview:infoViewContainer];
[pool drain];
}
-(void)viewDidLoad
{
[super viewDidLoad];
}
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[UIView animateWithDuration:5.0 animations:^{
self.keypadViewContainer.frame = CGRectMake(0, 0, 320, 200);
} completion:NULL];
}
-(void)dealloc
{
[buttons release];
[passcodeFields release];
[buttonBackgroundImage release];
[buttonBackgroundHighlightedImage release];
[screenBackgroundImage release];
[infoView release];
[keypadView release];
[passcodeFieldsView release];
[infoViewContainerImage release];
[keypadViewContainerImage release];
[passcodeFieldsContainerImage release];
[infoViewImage release];
[passcodeViewImage release];
[infoToDisplayView release];
[super dealloc];
}
#end
I have a small feeling it may have something to do with the way I'm dealing with my views, so there's the whole source code.
Any help with this will be highly appreciated.
Instead of those :
keypadViewContainer = [[[UIView alloc] initWithFrame:CGRectMake(0, 261, 320, 200)] autorelease];
Use
Self.keypadViewContainer = .....
and your #synthesize are wrong.
You declare iVars explicitly without underscore,
But use synthesize to create underscored iVars.
So your properties correspond to
_keypadViewContainer
but in your loadView you assign to keypadViewController
Quickest fix: just use #synthesize instead of synthesize = ...
(that is only if you don't use Xcode 4.4!)
Best fix: get rid of the explicit iVar declaration and
Make sure to use _keypadViewContainer etc. when you access iVar directly like in dealloc.
Ideal fix: use ARC and use IB to build your keypad interface (why don't you btw?)

Connect a UITapGestureRecognizer to a UIView

I'm trying to connect a gesture to a UIView so I can tap on the object, but it is not working. What am I doing wrong?
Shape.h
#import <UIKit/UIKit.h>
#interface Shape : UIView;
- (id) initWithX: (int)xVal andY: (int)yVal;
#end
Shape.m
#import "Shape.h"
#implementation Shape
- (id) initWithX:(int )xVal andY:(int)yVal {
self = [super init];
UIView *shape = [[UIView alloc] initWithFrame:CGRectMake(xVal, yVal, 10, 10)];
shape.backgroundColor = [UIColor redColor];
shape.userInteractionEnabled = YES;
[self addSubview:shape];
return self;
}
#end
MODIFIED CODE: The following code is in the main ViewController. I have removed the UITapGestureRecognizer from the Shape class. The code works if I make the following change, but then it is 'box' that responds to the tap gesture, not 'shape':
[shape addGestureRecognizer:tap];
to
[box addGestureRecognizer:tap];
- (void)handlerTap:(UITapGestureRecognizer *)recognizer {
//CGPoint location = [recognizer locationInView:[recognizer.view superview]];
NSLog(#"Success");
}
-(void)drawShapes{
NSLog(#"Draw");
if(!box){
box = [[UIView alloc] initWithFrame:CGRectMake(0, 0, screenWidth, screenHeight-100)];
box.backgroundColor = [UIColor colorWithRed: 0.8 green: 0.8 blue: 0.0 alpha:0.2];
[self.view addSubview:box];
}
for (int i = 0; i<5; i++) {
int x = arc4random() % screenWidth;
int y = arc4random() % screenHeight;
Shape * shape =[[Shape alloc] initWithX:x andY:y ];
[box addSubview:shape];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] init];
[tap setNumberOfTapsRequired:1];
[tap addTarget:self action:#selector(handlerTap:)];
[box addGestureRecognizer:tap];
}
}
SOLUTION: I have learned that
self = [super init];
needs to be changed to include a CGRECT that defines the boundaries of the view that *shape is placed into.
self = [super initWithFrame:CGRectMake(xVal, yVal, 10, 10)];
Also, *shape needs to be placed at 0,0 to ensure its correct placement within its parent.
UIView *shape = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
#import "Shape.h"
#implementation Shape
- (id) initWithX:(int )xVal andY:(int)yVal {
self = [super initWithFrame:CGRectMake(xVal, yVal, 10, 10)];
UIView *shape = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 10, 10)];
shape.backgroundColor = [UIColor redColor];
shape.userInteractionEnabled = YES;
[self addSubview:shape];
return self;
}
#end
You should set the target of the gesture recognizer to self, not the view, because you implemented the handlerTap: method in the Shape class.

Objective C implementing a UIPickerView with a "Done" button

I am trying to implement a "Done" button in a UIPickerView Similar to the one under this link
I looked in the class reference but I couldn t find it
Thanks
The easiest way to do it is to model it in Interface Builder. It is a UIView containing a UIToolbar and a UIPickerView.
Then create an outlet for the UIView and connect it.
If you then have a UITextField you can assign your custom view to its inputView property.
[self.textField setInputView:self.customPicker];
Alternatively you can add the picker to your main view...
- (void)viewDidLoad
{
[super viewDidLoad];
self.customPicker.frame = CGRectMake(0, CGRectGetMaxY(self.view.frame), CGRectGetWidth(self.customPicker.frame), CGRectGetHeight(self.customPicker.frame));
[self.view addSubview:self.customPicker];
}
... and then use this method to show or hide the picker.
- (void)setPickerHidden:(BOOL)hidden
{
CGAffineTransform transform = hidden ? CGAffineTransformIdentity : CGAffineTransformMakeTranslation(0, -CGRectGetHeight(self.customPicker.frame));
[UIView animateWithDuration:0.3 animations:^{
self.customPicker.transform = transform;
}];
}
I added a UIToolbar with a UIBarButtonItem for the 'done' button in my xib with the frame set so that it's not initially visible (y value equal to the height of the parent view).
Every time the user access the picker, I changed the frame (the y value) of the UIDatePicker and the UIToolbar with an animation so that it slides up along with the picker from the bottom of the screen similar to the keyboard.
Check out my code below.
- (IBAction)showPicker
{
if(pickerVisible == NO)
{
// create the picker and add it to the view
if(self.datePicker == nil) self.datePicker = [[[UIDatePicker alloc] initWithFrame:CGRectMake(0, 460, 320, 216)] autorelease];
[self.datePicker setMaximumDate:[NSDate date]];
[self.datePicker setDatePickerMode:UIDatePickerModeDate];
[self.datePicker setHidden:NO];
[self.view addSubview:datePicker];
// the UIToolbar is referenced 'using self.datePickerToolbar'
[UIView beginAnimations:#"showDatepicker" context:nil];
// animate for 0.3 secs.
[UIView setAnimationDuration:0.3];
CGRect datepickerToolbarFrame = self.datePickerToolbar.frame;
datepickerToolbarFrame.origin.y -= (self.datePicker.frame.size.height + self.datePickerToolbar.frame.size.height);
self.datePickerToolbar.frame = datepickerToolbarFrame;
CGRect datepickerFrame = self.datePicker.frame;
datepickerFrame.origin.y -= (self.datePicker.frame.size.height + self.datePickerToolbar.frame.size.height);
self.datePicker.frame = datepickerFrame;
[UIView commitAnimations];
pickerVisible = YES;
}
}
- (IBAction)done
{
if(pickerVisible == YES)
{
[UIView beginAnimations:#"hideDatepicker" context:nil];
[UIView setAnimationDuration:0.3];
CGRect datepickerToolbarFrame = self.datePickerToolbar.frame;
datepickerToolbarFrame.origin.y += (self.datePicker.frame.size.height + self.datePickerToolbar.frame.size.height);
self.datePickerToolbar.frame = datepickerToolbarFrame;
CGRect datepickerFrame = self.datePicker.frame;
datepickerFrame.origin.y += (self.datePicker.frame.size.height + self.datePickerToolbar.frame.size.height);
self.datePicker.frame = datepickerFrame;
[UIView commitAnimations];
// remove the picker after the animation is finished
[self.datePicker performSelector:#selector(removeFromSuperview) withObject:nil afterDelay:0.3];
}
}
I create a custom class, this supports multiple orientation:
DateTimePicker.h
#interface DateTimePicker : UIView {
}
#property (nonatomic, assign, readonly) UIDatePicker *picker;
- (void) setMode: (UIDatePickerMode) mode;
- (void) addTargetForDoneButton: (id) target action: (SEL) action;
#end
DateTimePicker.m
#define MyDateTimePickerToolbarHeight 40
#interface DateTimePicker()
#property (nonatomic, assign, readwrite) UIDatePicker *picker;
#property (nonatomic, assign) id doneTarget;
#property (nonatomic, assign) SEL doneSelector;
- (void) donePressed;
#end
#implementation DateTimePicker
#synthesize picker = _picker;
#synthesize doneTarget = _doneTarget;
#synthesize doneSelector = _doneSelector;
- (id) initWithFrame: (CGRect) frame {
if ((self = [super initWithFrame: frame])) {
self.backgroundColor = [UIColor clearColor];
UIDatePicker *picker = [[UIDatePicker alloc] initWithFrame: CGRectMake(0, MyDateTimePickerToolbarHeight, frame.size.width, frame.size.height - MyDateTimePickerToolbarHeight)];
[self addSubview: picker];
UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame: CGRectMake(0, 0, frame.size.width, MyDateTimePickerToolbarHeight)];
toolbar.barStyle = UIBarStyleBlackOpaque;
toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth;
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithTitle: #"Done" style: UIBarButtonItemStyleBordered target: self action: #selector(donePressed)];
UIBarButtonItem* flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil];
toolbar.items = [NSArray arrayWithObjects:flexibleSpace, doneButton, nil];
[self addSubview: toolbar];
self.picker = picker;
picker.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleBottomMargin;
self.autoresizesSubviews = YES;
self.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight|UIViewAutoresizingFlexibleTopMargin|UIViewAutoresizingFlexibleBottomMargin;
}
return self;
}
- (void) setMode: (UIDatePickerMode) mode {
self.picker.datePickerMode = mode;
}
- (void) donePressed {
if (self.doneTarget) {
[self.doneTarget performSelector:self.doneSelector withObject:nil afterDelay:0];
}
}
- (void) addTargetForDoneButton: (id) target action: (SEL) action {
self.doneTarget = target;
self.doneSelector = action;
}
Using custom view in your view controller:
- (void)viewDidLoad
{
[super viewDidLoad];
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[button addTarget:self
action:#selector(buttonPressed:)
forControlEvents:UIControlEventTouchDown];
[button setTitle:#"Show picker" forState:UIControlStateNormal];
button.frame = CGRectMake(100, 50, 100, 40.0);
[self.view addSubview:button];
CGRect screenRect = [[UIScreen mainScreen] bounds];
CGFloat screenWidth = screenRect.size.width;
CGFloat screenHeight = screenRect.size.height;
picker = [[DateTimePicker alloc] initWithFrame:CGRectMake(0, screenHeight/2 - 35, screenWidth, screenHeight/2 + 35)];
[picker addTargetForDoneButton:self action:#selector(donePressed)];
[self.view addSubview:picker];
picker.hidden = YES;
[picker setMode:UIDatePickerModeDate];
}
-(void)donePressed {
picker.hidden = YES;
}
-(void)buttonPressed:(id)sender {
picker.hidden = NO;
}
Hope this helps. :)
There is a more elegant solution. I'm not sure if this is recent (as of iOS7), but this has been working for me splendidly.
TJDatePicker.h
#protocol TJDatePickerActionDelegate <NSObject>
- (void)cancel:(id)sender;
- (void)done:(id)sender;
#end
#interface TJDatePicker : UIDatePicker
#property (strong, nonatomic) UIView *navInputView;
#property (weak, nonatomic) id<TJDatePickerActionDelegate> actionDelegate;
#end
TJDatePicker.m
#import "TJDatePicker.h"
#interface TJDatePicker ()
#property (strong, nonatomic) TJButton *cancelButton;
#property (strong, nonatomic) TJButton *doneButton;
#end
#implementation TJDatePicker
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
[self updateSubviews];
}
return self;
}
- (void)layoutSubviews
{
[super layoutSubviews];
[self updateSubviews];
}
- (void)updateSubviews
{
self.navInputView.frame = CGRectMake(0, 0, self.width, 45);
self.cancelButton.frame = CGRectMake(5, 5, 80, 35);
CGFloat width = 80;
self.doneButton.frame = CGRectMake(CGRectGetMaxX(self.navInputView.frame) - width, self.cancelButton.frame.origin.y, width, self.cancelButton.height);
}
- (UIView *)navInputView
{
if (!_navInputView)
{
_navInputView = [[UIView alloc] init];
_navInputView.backgroundColor = [UIColor whiteColor];
self.cancelButton = [UIButton buttonWithType:UIButtonTypeCustom];
[self.cancelButton setTitle:#"CANCEL" forState:UIControlStateNormal];
[self.cancelButton addTarget:self action:#selector(cancelButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[_navInputView addSubview:self.cancelButton];
self.doneButton = [UIButton buttonWithType:UIButtonTypeCustom];
[self.doneButton setTitle:#"DONE" forState:UIControlStateNormal];
[self.doneButton addTarget:self action:#selector(doneButtonPressed) forControlEvents:UIControlEventTouchUpInside];
[_navInputView addSubview:self.doneButton];
}
return _navInputView;
}
- (void)cancelButtonPressed
{
[self.actionDelegate cancel:self];
}
- (void)doneButtonPressed
{
[self.actionDelegate done:self];
}
And then at implementation time...
self.datePicker = [[TJDatePicker alloc] init];
self.datePicker.actionDelegate = self;
self.textField.inputAccessoryView = self.datePicker.navInputView;
The key here is to use the inputAccessoryView of the UITextField that you are planning on setting the UIDatePicker to.
You get the "Done" button in the toolbar using the ActionSheetPicker. Its is a great alternative to building it yourself.
https://github.com/skywinder/ActionSheetPicker-3.0
Success! Ok, I would never suggest doing this, but here's where the done button is created in your particular tutorial code:
Looking at the storyboard, we can see that when you click the "Role" box within "AddPersonTVC.h" (class at the top right of the storyboard), it pops up a class called "RollPickerTVCell.h"
Looking into RollPickerTVCell.h, we notice that the whole class is a subclass of "CoreDataTableViewCell"
#interface RolePickerTVCell : CoreDataTableViewCell <UIPickerViewDataSource, UIPickerViewDelegate>
Looking at the class "CoreDataTableViewCell.m", we finally find our uibarbuttonitem!
UIBarButtonItem *doneBtn =[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(done:)];
In case you are working on a Table View Cell and you are not using a UITextField (hence you won't be using the Accessory View), here's what I did:
I created a table view cell called GWDatePickerCell that looks like this (no .nib files involved).
GWDatePickerCell.h:
#import <UIKit/UIKit.h>
#interface GWDatePickerCell : UITableViewCell
#property (nonatomic, strong) UIDatePicker *datePicker;
#property (nonatomic, strong) UIToolbar *toolbar;
#property (nonatomic, strong) UIBarButtonItem *buttonDone;
#end
GWDatePickerCell.m:
#import "GWDatePickerCell.h"
#implementation GWDatePickerCell
- (id) initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {
if(!(self=[super initWithStyle:style reuseIdentifier:reuseIdentifier])) return nil;
_datePicker = [[UIDatePicker alloc] init];
[_datePicker setMinuteInterval:5];
[_datePicker setDatePickerMode:UIDatePickerModeDateAndTime];
[self.contentView addSubview:_datePicker];
_toolbar = [[UIToolbar alloc] init];
_buttonDone = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:nil action:nil];
_toolbar.items = #[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil], _buttonDone];
[self.contentView addSubview:_toolbar];
return self;
}
- (void)layoutSubviews{
[super layoutSubviews];
CGRect r = self.contentView.bounds;
r.origin.y +=44;
r.size.height = 216;
CGRect tb = self.contentView.bounds;
tb.size.height = 44;
_datePicker.frame = r;
_toolbar.frame = tb;
}
#end
Now all I had to do when creating the cells in the Table View:
Specify the #selector for the Done button.
Set the correct cell height in heightForRowAtIndexPath

How to hide the keyboard if I have a UIView(contains several textview) in Scrollview

I have several textview in my UIVIew which contained in a scrollview.
First the scollview doesn't not actives when I touched it and want to hide the keyboard after finished the textview editing. So I had build a class name subUIView inherit from scrollview. In that class I overwrite the touch touchbegan events. like the code blow.
But after that the textviewbeingediting function didn't action any more. It's all about touchbegan events calling even when I want to edit the textview.
Could you offer me some advise to solve the problem?Thanks
//
// **subUIView.h**
#import <UIKit/UIKit.h>
#interface subUIView : UIScrollview
{
}
#end
// **subUIView.m**
#import "subUIView.h"
#implementation subUIView
- (id)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
self.delegate=self;
//return [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;}
NSInteger a=0;
- (void) touchesBegan: (NSSet *) touches withEvent: (UIEvent *) event { NSLog(#"touch began ");
// If not dragging, send event to next responder
if (!self.dragging)
{
[self.nextResponder touchesBegan: touches withEvent:event];
}}
in the code blow I alloc scrollview from subUIView and code the textviewbeginediting function.
//
// **ReadExperienceInfoViewController.h**
#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>
#define ExperienceTableName #"pockets"
#class subUIView;
#interface ReadExperienceInfoViewController : UIViewController <UITextFieldDelegate,UITextViewDelegate> {
subUIView *scrollView;
UIView *upView;
UITextField *bookNameTextField;
UITextView *bookExprection;
NSString *getFullDateStr;
BOOL dragging;
}
#property (nonatomic, retain) UIView *upView;
#property (nonatomic, retain) subUIView *scrollView;
//
// **ReadExperienceInfoViewController.m**
//- (void)loadView{
scrollView=[[subUIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
scrollView.contentSize=CGSizeMake(320, 960);
scrollView.backgroundColor=[UIColor colorWithPatternImage :[UIImage imageNamed:#"infomation.png"]];
scrollView.showsVerticalScrollIndicator=YES;
upView=[[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
upView=[[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 960)];
[upView setUserInteractionEnabled:YES];
UILabel *bookName = [[UILabel alloc] initWithFrame:CGRectMake(20, 20, 100, 30)];
bookName.backgroundColor = [UIColor clearColor];
bookName.text = #"Title";
bookName.font=[UIFont boldSystemFontOfSize:16];
[upView addSubview:bookName];
[bookName release];
bookNameTextField = [[UITextField alloc] initWithFrame:CGRectMake(20, 50, 280, 30)];
bookNameTextField.backgroundColor = [UIColor whiteColor];
bookNameTextField.returnKeyType=UIReturnKeyDone;
bookNameTextField.delegate=self;
[upView addSubview:bookNameTextField];
//lowerView=[[UIView alloc] initWithFrame:CGRectMake(0, 90, 320, 170)];
UILabel *bookExprectionLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 80, 200, 30)];
bookExprectionLabel.text = #"Content";
bookExprectionLabel.font=[UIFont boldSystemFontOfSize:16];
bookExprectionLabel.backgroundColor = [UIColor clearColor];
[upView addSubview:bookExprectionLabel];
[bookExprectionLabel release];
bookExprection = [[UITextView alloc] initWithFrame:CGRectMake(20, 110, 280, 140)];
bookExprection.backgroundColor = [UIColor whiteColor];
bookExprection.font = [UIFont systemFontOfSize:14];
bookExprection.delegate=self;
[upView addSubview:bookExprection];
self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:#"Save"
style:UIBarButtonItemStylePlain
target:self action:#selector(updateExperience)]
autorelease];
self.title= bookNameStr;
self.view=scrollView;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.3];
upView.frame=CGRectMake(0, 0, 320, 960);
[UIView commitAnimations];
[bookExprection resignFirstResponder];
[bookNameTextField resignFirstResponder];
}
-(void)textViewDidBeginEditing:(UITextView *)textView{
NSLog(#"texview dig begin editing");
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.3];
if (textView==bookExprection) {
upView.frame=CGRectMake(0, -80, 320, 0);
}
[UIView commitAnimations];
}
Your subUIView.h File must implement the UITextFieldDelegate Protocol, so your viewcontroller responds to the delegate methods for the text field.
Same for the Scroll view, you have to implement the ScrollView
//subUIView.h
#interface subUIView : UIViewController <UIScrollViewDelegate, UITextFieldDelegate>{
//do stuff
}
Then of course you must write scrollView.delegate = self; so that the viewcontroller responds to the delegatemethods for the scroll view.
Hope this helps