I am adding a uipickerview as the subview of the main view. To dismiss the pickerview on tapping the backgroud view, i am adding a UITapGestureRecognizer to the main view.
I am using the following code to add the GestureRecognizer for main view
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
gestureRecognizer.numberOfTapsRequired=1;
gestureRecognizer.numberOfTouchesRequired=1;
gestureRecognizer.delegate = self;
[self.view addGestureRecognizer:gestureRecognizer];
[gestureRecognizer release];
In the handleSingleTap method i am dismissing the pickerview.
But the problem is handleSingleTap is also called when I tap inside the pickerview. To avoid it i used the following delegate method of UIGestureRecognizer
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
/*
*If the tap is inside a button return NO, to ensure the button click is detected.
*/
if ([touch.view isKindOfClass:[UIButton class]]){
return FALSE;
}else if([touch.view isKindOfClass:[UIPickerView class]]) {
return FALSE;
}
return TRUE;
}
It is working for button,But is not working for UIPickerView. Can anyone help me with this?
I have coded up a solution to your particular requirement.
first, i implemented your code as you have described and observed the same problem you reported - spurious tap events being sent to tap handler, when you tapped on anything, including a UIButton.
this told me that the UITapGestureRecogniser was "stealing" the touches that should have gone to the UIButton, so i decided the simplest, most pragmatic solution was to use that feature to my advantage, and so i assigned a UITapGestureRecogniser to both the pickerview and the button also. the taps for the pickerview we just discard, the others we parse and pass on to the button's tap handler.
note - for expedience i assigned the pickerview's datasource and delegate in the xib. you will need to do that also, or set it in code.
header
//
// ViewController.h
// stackExchangeDemo
//
// Created by unsynchronized on 18/01/12.
// released to public domain via http://stackoverflow.com/a/8908028/830899
//
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
<UIPickerViewDelegate, UIPickerViewDataSource>
{
UIButton *btn1;
UIPickerView *picker1;
}
#property (retain, nonatomic) IBOutlet UIButton *btn1;
#property (retain, nonatomic) IBOutlet UIPickerView *picker1;
#end
implementation
//
// ViewController.m
// stackExchangeDemo
//
// Created by unsynchronized on 18/01/12.
// released to public domain via http://stackoverflow.com/a/8908028/830899
//
#import "ViewController.h"
#implementation ViewController
#synthesize btn1;
#synthesize picker1;
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
-(void) handleSingleTap:(UITapGestureRecognizer *) tapper {
if (tapper.state == UIGestureRecognizerStateEnded) {
NSLog(#"%#",NSStringFromSelector(_cmd));
}
}
- (IBAction)handleButtonTap:(id)sender {
NSLog(#"%#",NSStringFromSelector(_cmd));
}
-(void) handleButtonTapGesture:(UITapGestureRecognizer *) tapper {
// call the buttons event handler
UIControlEvents eventsToHandle = UIControlEventTouchUpInside;
if (tapper.state == UIGestureRecognizerStateEnded) {
UIButton *btn = (UIButton *) tapper.view;
for (NSString *selName in [btn actionsForTarget:self forControlEvent:eventsToHandle]) {
SEL action = NSSelectorFromString(selName);
if (action) {
[self performSelector:action withObject:btn1];
break;
}
};
}
}
-(void) handleDummyTap:(UITapGestureRecognizer *) tapper {
// silently ignore the tap event for this view.
}
-(void) setupTap:(UIView *) view action:(SEL)action {
// assign custom tap event handler for given view.
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:action];
[view addGestureRecognizer:gestureRecognizer];
[gestureRecognizer release];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self setupTap:self.view action:#selector(handleSingleTap:)];
[self setupTap:picker1 action:#selector(handleDummyTap:)];
[self setupTap:btn1 action:#selector(handleButtonTapGesture:)];
}
- (void)viewDidUnload
{
[self setBtn1:nil];
[self setPicker1:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
}
- (void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
#pragma mark #protocol UIPickerViewDataSource<NSObject>
// returns the number of 'columns' to display.
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
return 1;
}
// returns the # of rows in each component..
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
return 1;
}
#pragma mark #protocol UIPickerViewDelegate<NSObject>
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
return [#"so long and thanks for all the fish".copy autorelease ];
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
NSLog(#"%#",NSStringFromSelector(_cmd));
}
- (void)dealloc {
[btn1 release];
[picker1 release];
[super dealloc];
}
#end
It is possible that the view touched (touch.view) is one of the subviews of the pickerview. I'd try testing:
[[pickerview subviews] containsObject: touch.view];
I implemented the following in Swift:
override func viewDidLoad()
{
super.viewDidLoad()
let tap = UITapGestureRecognizer(target: self, action: #selector(handleTapGesture))
tap.cancelsTouchesInView = false
view.addGestureRecognizer(tap)
}
func handleTapGesture(sender: AnyObject)
{
let subview = view?.hitTest(sender.locationInView(view), withEvent: nil)
if(!(subview?.isDescendantOfView(timePicker) ?? false))
{//might want to add a condition to make sure it's not your button ^^
showTimePicker(false)//method which handles showing/hiding my picker
}
}
I simply added an invisible UIControl instance behind the UIPickerView, which covers all the window, and gets all the touches behind UIPickerView. If it is touched, then both the UIPickerView and the UIControl is dismissed. (SelectButton and CancelButton are accessory buttons to UIPickerView.)
#property (strong, nonatomic) UIControl *touchRecognizer;
- (IBAction)showPicker:(id)sender {
self.touchRecognizer = [[UIControl alloc]initWithFrame:self.view.window.bounds];
[self.view.window addSubview:self.touchRecognizer];
[self.touchRecognizer addTarget:self action:#selector(touchedOutsidePicker:) forControlEvents:UIControlEventTouchUpInside];
[self.textField becomeFirstResponder];
}
- (IBAction)touchedOutsidePicker:(id)sender {
[self.touchRecognizer removeFromSuperview];
self.touchRecognizer = nil;
[self.textField resignFirstResponder];
}
-(void)selectButtonPressed:(id)sender{
[self.touchRecognizer removeFromSuperview];
self.touchRecognizer = nil;
[self.textField resignFirstResponder];
}
-(void)cancelButtonPressed:(id)sender{
[self.touchRecognizer removeFromSuperview];
self.touchRecognizer = nil;
[self.textField resignFirstResponder];
}
Related
I have a custom UITableViewCell which has a text field inside it. I have created it using IB and have a custom class with it.
Now, my issue is that I want to setup the text field so that during text entry if the user clicks outside the text field (without hitting the return/done key on the keypad), the field resigns first responder. I understand, that do that I need to handle the Touch Up Inside Event. However my tableview class never receives this event even though I have done the connections. I am assuming that its because its not subclass of UIcontrol, which I cant make it as it needs to be UITableViewCel.
So whats the solution?? How do I receive these events??
Header File:
#import <UIKit/UIKit.h>
#interface MMSingleTextFieldCell : UITableViewCell <UITextFieldDelegate>
// Properties
#property (weak, nonatomic) IBOutlet UITextField *singleTextField;
// Methods
- (IBAction)eventTouchUpOutside:(id)sender;
- (IBAction)eventTouchUpInside:(id)sender;
#end
Class File:
#import "MMSingleTextFieldCell.h"
#implementation MMSingleTextFieldCell
#synthesize singleTextField;
- (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
if (self) {
// Initialization code
}
return self;
}
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
// Configure the view for the selected state
}
- (IBAction)eventTouchUpOutside:(id)sender {
[singleTextField resignFirstResponder];
}
- (IBAction)eventTouchUpInside:(id)sender {
[singleTextField resignFirstResponder];
}
I have just recently open sourced a project on Github that should make this all relatively easy to do. It includes a class that can be easily inserted into a cell and a sample project demonstrating its capabilities.
If you look in RootTableViewController's viewDidLoadMethod you will see that I am adding a gesture recognizer:
self.tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(dismissKeyboard)];
_tapGestureRecognizer.delegate = self;
_tapGestureRecognizer.cancelsTouchesInView = NO;
[self.tableView addGestureRecognizer:_tapGestureRecognizer];
Add the dismiss keyboard method:
- (void)dismissKeyboard {
[_textField resignFirstResponder];
}
Add a gesture recognizer callback (in RootTableViewController):
//see: http://stackoverflow.com/questions/7195661/why-is-uigesturerecognizer-being-called-on-my-textfield-clear-button
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if([touch.view isKindOfClass:[UITextField class]] ||
[touch.view isKindOfClass:[UIButton class]])
{
return NO;
}
return YES;
}
Of course, this means you have to make RootTableViewController adhere to the UIGestureRecognizerDelegate protocol (in the header file):
#interface RootTableViewController : UITableViewController<SATextFieldDelegate, UIGestureRecognizerDelegate>
If you want the user to scroll the table view and dismiss the keyboard implement the following table view delegate callback:
- (void)scrollViewWillBeginDragging:(UIScrollView *)activeScrollView {
if (_textField.isFirstResponder) {
[self dismissKeyboard];
}
}
I believe this is the function you want.
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
if (_textField.isFirstResponder) {
[self dismissKeyboard];
}
}
Try this:
1) Implement the UIGestureRecognizerDelegate protocol
2) In viewDidLoad for example, create the following
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(hideKeyboard:)];
tap.delegate = self;
[self.view addGestureRecognizer:tap];
3) Now, implement the method from protocol from 1
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
// Use this for allow some control to receive his natural tap event. You can use tap.cancelsTouchesInView = NO; in the 2 step instead of this, try both of then and choose on your own.
if (touch.view == <some control>) {
//NSLog(#"NO");
return NO;
}
//NSLog(#"YES");
return YES;
}
4) finally, implement the callback for tap
-(void) hideKeyboard:(id)sender{
if (<your edit text>.isEditing) {
[<your edit text> resignFirstResponder];
}
}
I hope this will help, or at least point you to the right direction
Ok I am trying to connect a UIPickerView with a custom class. The idea is to have 3 picker views in one normal view.
So far I have created one view and bound it to my class TestView.h
Then I added a picker view to the view in the storyboard (iOS 5)
I then created a class for this picker view:
#interface TestPickerView : UIPickerView <UIPickerViewDelegate, UIPickerViewDataSource>
{
NSArray *data;
}
Then tried to add a Property to my normal view (TestView.h)
#import "TestPickerView.h"
#interface TestView : UIViewController
#property (strong, nonatomic) IBOutlet TestPickerView *myTestPicker;
#end
But how do i bind the UIPickerView inside my normal view to this class/property?
I will in the end have 3 UIPickerView's and my idea was to have 3 references in my UIViewController to control these UIPickerViews. That way I could set the data (datasource) using the properties once when the normal view is loading and then the PickerViews would just show. Hopefully i would also be able to get notified in my normal view when the value in one of the views occur.
Please call your TestView >> TestViewController instead, as it is a controller.
In your storyboard, select the PickerView and change it's class name to TestPickerView.
After that just create your three IBOutlets and connect the PickerViews. That's it.
// edit: To explain, how you distinguish between the pickers. Make 3 outlets, e.g.:
IBOutlet TestPickerView *picker1;
IBOutlet TestPickerView *picker2;
IBOutlet TestPickerView *picker3;
And than in your delegate method, check which picker did call the delegate, e.g.:
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
if(pickerView == self.picker1)
{
// picker1
}
else if(pickerView == self.picker2)
{
// picker2
}
else
{
// picker3
}
}
Here you go dude, this is how I did it on several of my apps and games.
#import <UIKit/UIKit.h>
#pragma mark - Delegate Protocol
#protocol someDelegate
#required
-(void)somePickerFinishedPicking:(id)item;
#end
#pragma mark - Class interface
#interface SomePicker : UIViewController <UIPickerViewDelegate, UIPickerViewDataSource>
{
NSMutableArray* dataSource;
}
#pragma mark - Property Istantiation
#property (nonatomic, retain) NSMutableArray* dataSource;
#property (nonatomic, retain) id <someDelegate> pickDelegate;
#pragma mark - Constructors / Destructors
- (id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil;
- (void) didReceiveMemoryWarning;
- (void) dealloc;
- (void) createDataSource;
#pragma mark - View Lifecycle
- (void) viewDidLoad;
#pragma mark - UIPicker Protocols
-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component;
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView;
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component;
-(UIView*) pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view;
#pragma mark - Delegate Protocols
-(void) handlePickerDidFinish:(id)item;
#end
this for your .m
#pragma mark - Class Implementation
#implementation SomePicker
#pragma mark - Variable synthesize
// ARRAYS
#synthesize dataSource;
// DELEGATES
#synthesize pickDelegate = _pickDelegate;
#pragma mark - Constructors / Deconstructors
// Class initialization
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil;
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
dataSource = [[NSMutableArray alloc] init];
[self createDataSource];
}
return self;
}
// Handles memory warning events
- (void)didReceiveMemoryWarning
{
// Release the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
// Garbage Collection
- (void) dealloc;
{
// Release what you need
self.dataSource = nil;
[super dealloc];
}
// Creates the occasion entries for the picker
-(void)createDataSource
{
NSMutableDictionary* dataDictionary = [[NSMutableDictionary alloc] init];
// create your data source here or just forget about this and pass it from the parentViewController.
[dataDictionary release];
}
#pragma mark - View lifecycle
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad;
{
[super viewDidLoad];
UIPickerView* occasionsPicker = [[UIPickerView alloc] init];
[occasionsPicker setDataSource:self];
[occasionsPicker setDelegate:self];
[occasionsPicker setTag:888];
[occasionsPicker selectRow:500 inComponent:0 animated:YES];
[self.view addSubview:occasionsPicker];
[occasionsPicker release];
[self handlePickerDidFinish:[[self.dataSource objectAtIndex:(500 % self.dataSource.count)] objectForKey:#"key"]];
}
#pragma mark - UIPicker Protocols
// Creates the rows in the picker.
-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
// Endless roll illusion else just bind it to the size of the data source
return 1000;
}
// Determines the number of columns in the picker
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
// Add however many columns you need
return 1;
}
// Handles the event when the user picks a row.
-(void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component
{
//this does something with the row selected
[self handlePickerDidFinish:[[self.dataSource objectAtIndex:(row % self.dataSource.count)] objectForKey:#"key"]];
}
// Creates the custom view for each cell so the text shows in accordance to the App Style
-(UIView*) pickerView:(UIPickerView *)pickerView viewForRow:(NSInteger)row forComponent:(NSInteger)component reusingView:(UIView *)view
{
UILabel* customRowLabel = [[[UILabel alloc] initWithFrame:CGRectMake(0, 0, [pickerView rowSizeForComponent:component].width, [pickerView rowSizeForComponent:component].height)] autorelease];
customRowLabel.font = [UIFont fontWithName:#"HelveticaNeue" size: 16];
customRowLabel.textColor = [UIColor colorWithRed:kColorRed green:kColorGreen blue:kColorBlue alpha:1];
customRowLabel.textAlignment = UITextAlignmentCenter;
customRowLabel.backgroundColor = [UIColor clearColor];
customRowLabel.text = [[self.dataSource objectAtIndex:(row % self.dataSource.count)] objectForKey:#"key"];
return customRowLabel;
}
#pragma mark - Delegate Protocols
// Notifies Delegate class that an action has been perfomed and passes the Mood String selected
-(void)handlePickerDidFinish:(id)item
{
[self.pickDelegate somePickerFinishedPicking:item];
}
#end
And just instantiate it like so on your parent ViewController:
CGRect rectPicker = CGRectMake(60, 100, 200, 216);
self.somePicker = [[[SomePicker alloc] init] autorelease];
[self.somePicker setPickDelegate:self];
[self.somePicker.view setBackgroundColor:[UIColor clearColor]];
self.somePicker.view.frame = rectPicker;
[self.somePicker.view setTag:777];
[self.somePicker.view setAlpha:0];
[self.view addSubview:self.somePicker.view];
~/End of Line
I have been having trouble pulling up a custom UIPickerView from the textfield's inputview property. I have been working on this for awhile, did some research, and tried to put together a separate project based on Apple's UICatalog example.
However, whenever I tap inside the textfield all I get is a black screen that pops up in place of the picker view. Im sure I've overlooked something but I have been looking for days any help would be appreciated.
Keep in mind this was my test project to see if I could add this functionality to my other app and that a lot of the code I tried to copy from the UICatalog app. Sorry if anything doesn't make sense and please feel free to ask any questions you may have. Thank you.
// ViewController.h
// TestPicker
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UITextFieldDelegate,UIPickerViewDelegate,UIPickerViewDataSource>{
UIPickerView *picker;
//The picker view the textfield responds to.
IBOutlet UITextField *myText;
//The textfield which has the input view of a picker.
NSArray *testArray;
//The array which values are loaded into the picker.
}
#end
// ViewController.m
// TestPicker
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad
{
picker.delegate=self;
picker.dataSource=self;
myText.delegate=self;
[self createPicker];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
myText = nil;
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
else {
return YES;
}
}
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
picker = [[UIPickerView alloc] initWithFrame:CGRectZero];
myText.inputView=picker;
return YES;
}
-(void)textFieldDidBeginEditing:(UITextField *)textField{
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
NSString *returnStr = #"";
if (pickerView == picker)
{
if (component == 0)
{
returnStr = [testArray objectAtIndex:row];
}
else
{
returnStr = [[NSNumber numberWithInt:row] stringValue];
}
}
return returnStr;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
return [testArray count];
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
return 1;
}
- (void)createPicker
{
testArray = [NSArray arrayWithObjects:
#"John Appleseed", #"Chris Armstrong", #"Serena Auroux",
#"Susan Bean", #"Luis Becerra", #"Kate Bell", #"Alain Briere",
nil];
picker = [[UIPickerView alloc] initWithFrame:CGRectZero];
picker.showsSelectionIndicator = YES; // note this is default to NO
picker.delegate = self;
picker.dataSource = self;
}
#end
The problem is in this method:
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
picker = [[UIPickerView alloc] initWithFrame:CGRectZero];
myText.inputView=picker;
return YES;
}
You already created picker in your createPicker method, called from viewDidLoad, so this creates another instance (this instance won't have the delegate or data source set to self, since these were set on the first instance you created). If you just delete the first line of this method, it should work.
Two other comments on your code. The first 2 lines in the viewDidLoad method aren't doing anything since you haven't created picker yet -- they should be deleted. You also need to implement the pickerView:didSelectRow:inComponent: method in order to get the selected value of your picker into the text field.
I'm currently working on an Iphone application that has 3 text fields. If I connect the delegate of the first two text fields to the class then run the simulator and try to click on them nothing happens, they don't allow me to edit them and the keyboard doesn't pop up. If I don't connect their delegates then the keyboard appears but textFieldShouldReturn is never called when I click the done button on the keyboard. The third text field brings up a UIPickerView when clicked on and that shows up as expected.
LoginViewController.h
#import <UIKit/UIKit.h>
#interface LoginViewController : UIViewController <UITextFieldDelegate,UIPickerViewDelegate,UIPickerViewDataSource>
{
IBOutlet UITextField *usernameField;
IBOutlet UITextField *passwordField;
IBOutlet UITextField *conferenceField;
IBOutlet UIButton *loginButton;
//IBOutlet UIPickerView *picker;
ConnectHandler *cHandle;
NSMutableArray *conferences;
}
#property (nonatomic, retain) UITextField *usernameField;
#property (nonatomic, retain) UITextField *passwordField;
#property (nonatomic, retain) UITextField *conferenceField;
#property (nonatomic, retain) UIButton *loginButton;
- (IBAction) login: (id) sender;
#end
LoginViewController.m
#import "LoginViewController.h"
#implementation LoginViewController
#synthesize usernameField;
#synthesize passwordField;
#synthesize conferenceField;
#synthesize loginButton;
// The designated initializer. Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
/*
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization.
}
return self;
}
*/
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
[super viewDidLoad];
cHandle = [ConnectHandler new];
NSArray *confs = [cHandle conference_list];
//conferences = confs;
// temporary to test if it's working
conferences = [NSArray arrayWithObjects:#"Germany", #"Austria", #"Swiss", #"Luxembourg",
#"Spain", #"Netherlands", #"USA", #"Canada", #"Denmark", #"Great Britain",
#"Finland", #"France", #"Greece", #"Ireland", #"Italy", #"Norway", #"Portugal",
#"Poland", #"Slovenia", #"Sweden", nil];
UIPickerView *picker = [[UIPickerView alloc] initWithFrame:CGRectZero];
picker.delegate = self;
picker.dataSource = self;
[picker setShowsSelectionIndicator:YES];
[conferenceField setInputView:picker];
[picker release];
[picker selectRow:1 inComponent:0 animated:NO];
}
-(BOOL)textFieldShouldReturn:(UITextField*)textField {
NSLog(#"TextFieldShouldReturn");
[textField resignFirstResponder];
return YES;
}
// Override to allow orientations other than the default portrait orientation.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Return YES for supported orientations.
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (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 {
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[super dealloc];
[conferences release];
}
- (IBAction) login: (id) sender
{
loginButton.enabled = FALSE;
NSLog(#"user: %# pass: %#", usernameField.text, passwordField.text);
//checks to see if user provided information is valid
NSString *db = #"sdfsdf";
BOOL auth = [cHandle check_auth:db :usernameField.text :[cHandle hashPass:passwordField.text]];
NSLog(#"AUTH: %#", auth?#"YES":#"NO");
// login successful if check_auth returns YES
if (auth == YES) {
// store the user's login info
// switch to full app
[self dismissModalViewControllerAnimated:YES];
}
else {
// display error message and stay on login screen
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Invalid"
message:[NSString stringWithFormat:#"The login or password you have entered is invalid"]
delegate:nil
cancelButtonTitle:#"Okay"
otherButtonTitles:nil];
[alert show];
[alert release];
loginButton.enabled = TRUE;
}
//NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
}
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
[textField resignFirstResponder];
//[pickerView setHidden:NO];
}
//#pragma mark -
//#pragma mark UIPickerViewDelegate
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component
{
NSLog(#"titleForRow");
return #"TEST"; //[conferences objectAtIndex:row];
}
- (void) pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent: (NSInteger)component
{
NSLog(#"didSelectRow");
[self textFieldShouldReturn:conferenceField];
// [pickerView resignFirstResponder];
//conferenceField.text = (NSString *)[conferences objectAtIndex:row];
}
//#pragma mark -
//#pragma mark UIPickerViewDataSource
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView
{
NSLog(#"numberOfComponentsInPickerView");
return 1;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component
{
NSLog(#"numberOfRowsInComponent");
return 4; //[conferences count];
}
#end
Add this to your viewDidLoad:
usernameField.delegate = self;
passwordField.delegate = self;
conferenceField.delegate = self;
You're not settings the delegate for the text fields. Also remove the resignFirstResponder code from your textFieldDidBeginEditing as mentioned in the other answers.
You have [textField resignFirstResponder] in the delegate method - (void)textFieldDidBeginEditing: which would make the keyboard go away prematurely.
This is your problem:
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
[textField resignFirstResponder];
//[pickerView setHidden:NO];
}
With the delegate hooked up, it’s receiving the -textFieldDidBeginEditing: message when the user touches the text field and immediately forcing the text field to resign first-responder status (i.e. lose its keyboard). Keep the delegate connected, remove the -resignFirstResponder call, and it’ll work.
I am using a UITEXTVIEW. I am trying to send a resignFirstResponder when the done button is pressed. I am not sure how to trigger the method containing the resignFirstResponder line.
I have set the UITextView's delegate to the File's Owner in Interface Builder. This is my viewcontroller's header and implementation file:
#import <Foundation/Foundation.h>
#import "Question.h"
#interface CommentQuestionViewController : UIViewController {
Question *question;
IBOutlet UILabel *questionTitle;
IBOutlet UITextView *inputAnswer; //this is the textview
}
#property (nonatomic, retain) UILabel *questionTitle;
#property (nonatomic, retain) Question *question;
#property (nonatomic, retain) UITextView *inputAnswer;
- (void) addButton:(id)sender isLast:(BOOL)last;
- (void) setQuestionId:(NSString*)quId withTitle:(NSString*)quTitle number:(NSString*)quNum section:(NSString*)sId questionType:(NSString*)qt;
#end
#import "CommentQuestionViewController.h"
#implementation CommentQuestionViewController
#synthesize questionTitle, question, inputAnswer;
- (void) addButton:(id)delegate isLast:(BOOL)last{
UIBarButtonItem *anotherButton;
anotherButton = [[UIBarButtonItem alloc] initWithTitle:#"Done" style:UIBarButtonItemStylePlain target:delegate action:#selector(finishQuestionnaire:)];
self.navigationItem.rightBarButtonItem = anotherButton;
[anotherButton release];
}
-(void)viewDidLoad{
//self.questionTitle.text = question.qTitle;
[[self questionTitle] setText:[question qTitle]];
[super viewDidLoad];
NSString *str = [NSString stringWithFormat:#"Question %#", [question qNumber]];
//self.title = str;
[self setTitle:str];
[str release];
}
-(void) setQuestionId:(NSString*)quId withTitle:(NSString*)quTitle number:(NSString*)quNum section:(NSString*)sId questionType:(NSString*)qt{
question = [[Question alloc]init];
[question setQId:quId];
[question setQTitle:quTitle];
[question setQNumber:quNum];
[question setSectionId:sId];
[question setQType:qt];
}
- (void) viewWillAppear:(BOOL)animated{
self.navigationItem.hidesBackButton = YES;
}
- (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) textViewDidEndEditing:(UITextView*)textView{
[textView resignFirstResponder];
}
- (void)viewDidUnload {
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (void)dealloc {
[inputAnswer release];
[questionTitle release];
[question release];
[super dealloc];
}
You can try this:
–(BOOL)textView:(UITextView*)textView shouldChangeCharactersInRange:(NSRange)range replacementText:(NSString*)text {
if ([text isEqualToString:#"\n"]) {
[textView resignFirstResponder];
return NO;
}
else
return YES;
}
Of course, you won't be able to type actual carriage returns if you do this.
After looking at your source code, the link that I had posted is pointless. I thought you were talking about the done key on the keyboard. But now I see that you were talking about an instance UIButton on the navigation bar, right?
Your addButton:isLast: method is looking great so far, but I'd change it a bit so it adheres to the Apple HIG:
- (void)addButton:(id)delegate isLast:(BOOL)last
{
UIBarButtonItem *anotherButton;
anotherButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:delegate
action:#selector(finishQuestionnaire:)];
self.navigationItem.rightBarButtonItem = anotherButton;
[anotherButton release];
}
It's pretty much the same, except this one creates a button with the appropriate style.
Anyway, I don't see how the button is being added since addButton:isLast: is not being called in viewDidLoad:. Add the following line in your viewDidLoad:.
[self addButton:self isLast:NO];
last is redundant in your addButton:isLast: since it's not even being use so I just pass whatever (NO).
You're almost done, but if you press that button, your application would crash since finishQuestionnaire: is not implemented on self (CommentQuestionViewController). And since you want to dismiss the keyboard when the user presses your done button, that's where we will also resign your text view as first responder. Just add the following method:
- (void)finishQuestionnaire:(id)sender
{
[inputAnswer resignFirstResponder];
}
It's BOOL that's it..
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
if([text isEqualToString:#"\n"]) {
[textView resignFirstResponder];
return NO;
}
return YES;
}
If that doesn't work please check the following things..
Whether your textView is connected to the textView property defined in your class.. (You can see this in your xib, with an arrow icon).
2.Check whether the textView delegate is written in your .h file.
#interface YourViewController : UIViewController <UITextViewDelegate>
3.Check whether the textView's delegate is assigned.
//set this in the viewDidLoad method
self.textView.delegate = self;
Check for new line character by this method.
-(NSRange)rangeOfCharacterFromSet:(NSCharacterSet *)aSet
Then check the length of the text, if it is one character length, then new line character is entered, not pasted.
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
BOOL hasNewLineCharacterTyped = (text.length == 1) && [text rangeOfCharacterFromSet:[NSCharacterSet newlineCharacterSet]].location != NSNotFound;
if (hasNewLineCharacterTyped) {
[textView resignFirstResponder];
return NO;
}
return YES;
}