I got error when passing arguments in #selector method.
This is my code:
-(void) accessoryView : (UITextField*) textField
{
UIToolbar* numberToolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 50)];
numberToolbar.barStyle = UIBarStyleBlackTranslucent;
numberToolbar.items = #[[[UIBarButtonItem alloc]initWithTitle:#"Cancel" style:UIBarButtonItemStyleBordered target:self action:#selector(cancelNumberPad )],
[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],
[[UIBarButtonItem alloc]initWithTitle:#"Apply" style:UIBarButtonItemStyleDone target:self action:#selector(doneWithNumberPad:textField:)]];
[numberToolbar sizeToFit];
textField.inputAccessoryView = numberToolbar;
}
-(void)doneWithNumberPad : (UITextField*) txt : (id) sender {
}
You can take help of reference variable for your textfield. Declare a global property as textfield. Keep a refernce of currently active textfield and access it in every method as per your requirement.
UITextField *activeTextField;
// UITextField Delegates
-(void)textFieldDidBeginEditing:(UITextField *)textField {
activeTextField = textField;
}
You can use this activeTextField property in your class anywhere.
You need to define your class as delegate of UITextField.
self.yourTextField.delegate = self
First: Your selector is wrong. I should be action:#selector(doneWithNumberPad::) or renaming your second method to -(void)doneWithNumberPad : (UITextField*) txt textField: (id) sender.
BUT Second: You can't send custom, additional parameters with an action method. You should access the text field over a property. In your case you can store the current text field in a property, when the editing in the text fields begin. Your view controller should implement UITextFieldDelegate to receive this event.
Related
I have a scene in which I want to use picker views to get the input for multiple text boxes. I want each picker view to have a toolbar with a "Done" button that dismisses the picker view. So far I have:
//toolbar with "Done" button for picker views
UIToolbar *pickerToolBar= [[UIToolbar alloc] initWithFrame:CGRectMake(0,0,320,44)];
[pickerToolBar setBarStyle:UIBarStyleBlackOpaque];
UIBarButtonItem *barButtonDone = [[UIBarButtonItem alloc] initWithTitle:#"Done"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(doneWithPicker:)];
pickerToolBar.items = [[NSArray alloc] initWithObjects:barButtonDone,nil];
barButtonDone.tintColor=[UIColor blackColor];
//set up picker views
_pickerOne = [[UIPickerView alloc] init];
_pickerOne.dataSource = self;
_pickerOne.delegate = self;
self.textFieldOne.inputView = self.pickerOne;
self.textFieldOne.inputAccessoryView = pickerToolBar;
What I need is some way for the doneWithPicker method to figure out which text field is currently being edited and call resignFirstResponder.
Use the text field delegate to identify which field is active. (Make sure to set yourself up as the delegate)
#implementation WhateverViewController
{
UITextField *activeTextField;
}
...
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
activeTextField = textField;
}
Then, in the method that is called when your done button is tapped:
[activeTextField resignFirstResponder];
The accessibility identifier is a developer generated ID for GUI objects, which can be used for automation tests.
A UIBarButtonItem does not implement UIAccessibilityIdentification. However is there a possibility that I can assign an accessibility identifier?
You could subclass UIBarButtonItem and implement the UIAccessibilityIdentification protocol in that subclass, lets's say BarButtonWithAccesibility.
In BarButtonWithAccesibility.h:
#interface BarButtonWithAccesibility : UIBarButtonItem<UIAccessibilityIdentification>
#property(nonatomic, copy) NSString *accessibilityIdentifier NS_AVAILABLE_IOS(5_0);
The only (strict) requirement for adhering to this protocol is defining the accessibilityIdentifier property.
Now in your view controller, let's say in viewDidLoad, you could set up a UIToolbar and add your subclassed UIBarButtonItem:
#import "BarButtonWithAccesibility.h"
- (void)viewDidLoad{
[super viewDidLoad];
UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
BarButtonWithAccesibility *myBarButton = [[BarButtonWithAccesibility alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(buttonPressed:)];
myBarButton.accessibilityIdentifier = #"I am a test button!";
toolbar.items = [[NSArray alloc] initWithObjects:myBarButton, nil];
[self.view addSubview:toolbar];
}
And within the buttonPressed: you could verify that you have access to the accessibilityIdentifier:
- (void)buttonPressed:(id)sender{
if ([sender isKindOfClass:[BarButtonWithAccesibility class]]) {
BarButtonWithAccesibility *theButton = (BarButtonWithAccesibility *)sender;
NSLog(#"My accesibility identifier is: %#", theButton.accessibilityIdentifier);
}
}
Hope this helps.
As of iOS 5 you can do it like this:
UIBarButtonItem *btn = [[UIBarButtonItem alloc] init...;
btn.accessibilityLabel = #"Label";
If you have UIToolbar created inside that if you want to create multiple UIBarButtonItem programatically then it can be accessed like that and set accessibilityLabel as well like that below:-
-(void)viewDidAppear:(BOOL)animated
{
UIBarButtonItem *infoButtonItem=[[UIBarButtonItem alloc]initWithTitle:#"info" style:UIBarButtonItemStyleBordered target:self action:#selector(infoButtonClicked)];
[self.customToolBar setItems:[NSArray arrayWithObject:infoButtonItem]];
//Here if you have muliple you can loop through it
UIView *view = (UIView*)[self.customToolBar.items objectAtIndex:0];
[view setAccessibilityLabel:NSLocalizedString(#"Test", #"")];
}
The subclassing UIBarButtonItem is a good solution. Depending on your needs, though, it may make more sense to simply assign the accessibilityIdentifier to the custom image of your UIBarButtonItem, assuming your UIBarButtonItem uses a custom image.
Having a slight problem here.
The (IBAction) method I have set up for UITextfields EditingDidChange is not being called when the textField is changed when using a UIPickerView as input.
However, it works fine when using keyboard input.
Does the UIPickerView not send out its current selection until it's dismissed or something?
An alternative is to probably use the UIPickerView method, didSelectRow to perform the updates I'm after.
Is there there a unique way I'm unaware of that will get this to work how I want?
I think that you have something like this to setup your text field:
self.citys = #[#"Buenos Aires", #"Bahia Blanca", #"Azul",#"Pigue"];
self.namePicker = [[UIPickerView alloc] init];
self.namePicker.delegate = self;
self.namePicker.dataSource = self;
self.namePicker.showsSelectionIndicator = YES;
self.accessoryView = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(onNameSelection)];
[self.accessoryView setItems:[NSArray arrayWithObject:doneButton]];
self.textField.inputView = self.namePicker;
self.textField.inputAccessoryView = self.accessoryView;
And something like this to set the text when the user finish the selection:
- (void) onNameSelection{
NSInteger row = [self.namePicker selectedRowInComponent:0];
self.textField.text = [self.citys objectAtIndex:row];
[self.textField resignFirstResponder];
}
So... You don't need the action EditingChanged, because you know when the textfield.text is changed.
Maybe you also have something like this to change the text while the user select row in the picker:
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component{
self.textField.text = [self.citys objectAtIndex:row];
}
Again, you know when the textfield.text is changed.
So... Because YOU are the responsible of the changes on the textfield.text YOU are the responsible of call the function associated to the EditingChanged action.
Here is a screenshot of what I did till now:
So what I am trying to do is when you select "pick a name" Textfield I need a Picker to show up, with the input #"Jack".
Since iOS 3.2, UITextField supports the inputView property to assign a custom view to be used as a keyboard, which provides a way to display a UIPickerView:
You could use the inputView property of the UITextField, probably combined with the inputAccessoryView property. You assign your pickerView to the inputView property, and, to dismiss the picker, a done button to the inputAccessoryView property.
UIPickerView *myPickerView = [[UIPickerView alloc] init];
//myPickerView configuration here...
myTextField.inputView = myPickerView;
Like that. This will not give you a direct way to dismiss the view since your UIPickerView has no return button, which is why I recommend to use the inputAccessoryView property to display a toolbar with a done button (the bar is just for aesthetics, you might as well just use a UIButton object):
UIToolbar *myToolbar = [[UIToolbar alloc] initWithFrame:
CGRectMake(0,0, 320, 44)]; //should code with variables to support view resizing
UIBarButtonItem *doneButton =
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone
target:self action:#selector(inputAccessoryViewDidFinish)];
//using default text field delegate method here, here you could call
//myTextField.resignFirstResponder to dismiss the views
[myToolbar setItems:[NSArray arrayWithObject: doneButton] animated:NO];
myTextField.inputAccessoryView = myToolbar;
I use this and find this a lot cleaner than adding a subview and animating the UIPicker
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
responder = textField;
if ([textField isEqual:self.txtBirthday]) {
UIDatePicker *datepicker = [[UIDatePicker alloc] initWithFrame:CGRectZero];
[datepicker setDatePickerMode:UIDatePickerModeDate];
textField.inputView = datepicker;
}
return YES;
}
it will work for you .. i have edited it .and for that you have to set delegate for textfield. and create a UIPIckrView in NIb file.
- (BOOL) textFieldShouldBeginEditing:(UITextView *)textView
{
pickrView.frame = CGRectMake(0, 500, pickrView.frame.size.width, pickrView.frame.size.height);
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:.50];
[UIView setAnimationDelegate:self];
pickrView.frame = CGRectMake(0, 200, pickrView.frame.size.width, pickrView.frame.size.height);
[self.view addSubview:pickrView];
[UIView commitAnimations];
return NO;
}
Well, you could rely on the UITextFieldDelegate to handle this kind of functionality.
Inside the
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
is where you would set the text of your current UITextField as well as initializing and showing the UIPickerView.
Important notice:
You might also want to conform to the UIPickerViewDelegate.
HTH
Swift:
internal var textFieldHandlerToolBar: UIToolbar = {
let tb = UIToolbar.init(frame: CGRect.init(origin: .zero, size: CGSize.init(width: UIScreen.main.bounds.width, height: 44.0)))
let doneBarButton = UIBarButtonItem.init(title: "Done", style: UIBarButtonItemStyle.done, target: self, action: #selector(actionDonePickerSelection))
tb.setItems([doneBarButton], animated: false)
return tb
}()
internal var pickerView: UIPickerView = {
let pv = UIPickerView.init()
return pv
}()
#objc internal func actionDonePickerSelection() {
textField.resignFirstResponder()
}
override func viewDidLoad() {
super.viewDidLoad()
self.pickerView.delegate = self
self.pickerView.datasource = self
}
Use it like this:
textField.inputAccessoryView = self.textFieldHandlerToolBar
textField.inputView = self.pickerView
What you can do is, create a UIButton with custom type on UITextField. Both having equal sizes. On the touch of button you can show UIPickerView.
http://tmblr.co/ZjkSZteCOUBS
I have the code and everything laid out in my blog to do this exactly. But below, I have the basic concept laid out.
Basically the solution involves an opensource project called ActionSheetPicker on github, and implementing the function textFieldShouldBeginEditing on the UITextFieldDelegate. You can dismiss the keyboard there and provide a UIPickerView instead. The basic code is listed here:
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
// We are now showing the UIPickerViewer instead
// Close the keypad if it is showing
[self.superview endEditing:YES];
// Function to show the picker view
[self showPickerViewer :array :pickerTitle];
// Return no so that no cursor is shown in the text box
return NO;
}
ViewController.h
#interface ChangeCurrencyVC : UIViewController <UIPickerViewDataSource, UIPickerViewDelegate>
{
NSArray *availableCurreniesArray;
}
#property (weak, nonatomic) IBOutlet UITextField *chooseCurrencyTxtFldRef;
ViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
availableCurreniesArray = #[#"Indian Rupee", #"US Dollar", #"European Union Euro", #"Canadian Dollar", #"Australian Dollar", #"Singapore Dollar", #"British Pound", #"Japanese Yen"];
// Do any additional setup after loading the view.
[self pickerview:self];
}
#pragma mark - picker view Custom Method
-(void)pickerview:(id)sender{
UIPickerView *pickerView = [[UIPickerView alloc] initWithFrame:CGRectMake(0, 0, 0, 0)];
pickerView.showsSelectionIndicator = YES;
pickerView.dataSource = self;
pickerView.delegate = self;
// set change the inputView (default is keyboard) to UIPickerView
self.chooseCurrencyTxtFldRef.inputView = pickerView;
// add a toolbar with Cancel & Done button
UIToolbar *toolBar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)];
toolBar.barStyle = UIBarStyleBlackOpaque;
UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(doneTouched:)];
UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:#selector(cancelTouched:)];
// the middle button is to make the Done button align to right
[toolBar setItems:[NSArray arrayWithObjects:cancelButton, [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil], doneButton, nil]];
self.chooseCurrencyTxtFldRef.inputAccessoryView = toolBar;
}
#pragma mark - doneTouched
- (void)cancelTouched:(UIBarButtonItem *)sender{
// hide the picker view
[self.chooseCurrencyTxtFldRef resignFirstResponder];
}
#pragma mark - doneTouched
- (void)doneTouched:(UIBarButtonItem *)sender{
// hide the picker view
[self.chooseCurrencyTxtFldRef resignFirstResponder];
// perform some action
}
#pragma mark - The Picker Challenge
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
return 1;
}
-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
return [availableCurreniesArray count];
}
- (nullable NSString *)pickerView:(UIPickerView *)pickerView titleForRow: (NSInteger)row forComponent:(NSInteger)component{
return availableCurreniesArray[row];
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
self.chooseCurrencyTxtFldRef.text = availableCurreniesArray[row];
}
I want to hide (resignFirstResponder) the virtual keyboard of UITextView when 'Done' presses. Theres no 'Did End on Exit' in UITextView. In UITextField i connect the 'Did End on Exit' with an IBAction and call resignFirstResponder method. How can i do this with UITextView?
The correct way to handle this is to add a done button in an inputAccessoryView to the UITextView. The inputAccessoryView is the bar that sometimes appears above the keyboard.
In order to implement the inputAccessoryView simply add this method (or a variation thereof) and call it in viewDidLoad.
- (void)addInputAccessoryViewForTextView:(UITextView *)textView{
//Create the toolbar for the inputAccessoryView
UIToolbar* toolbar = [[UIToolbar alloc]initWithFrame:CGRectMake(0, 0, 320, 50)];
[toolbar sizeToFit];
toolbar.barStyle = UIBarStyleBlackTranslucent;
//Add the done button and set its target:action: to call the method returnTextView:
toolbar.items = [NSArray arrayWithObjects:[[UIBarButtonItem alloc]initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],
[[UIBarButtonItem alloc]initWithTitle:#"Done" style:UIBarButtonItemStyleDone target:self action:#selector(returnTextView:)],
nil];
//Set the inputAccessoryView
[textView setInputAccessoryView:toolbar];
}
Then handel the button being pressed by implementing the action method you called with resignFirstResponder.
- (void) returnBreakdown:(UIButton *)sender{
[self.textView resignFirstResponder];
}
This should result in a working "Done" button appearing in a standard toolbar above the keyboard.
I'm assuming by the "Done" button you mean the return key. It's not as intuitive as you might think. This question covers it pretty well.
you could add this to an action if you want to be able to use your return key
[[self view] endEditing: YES];
Make sure you declare support for the UITextViewDelegate protocol.
#interface ...ViewController : UIViewController` in .h file. In .m file, implement below method
-(BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
if([text isEqualToString:#"\n"]) {
[textView resignFirstResponder];
return NO;
}
return YES; }
Here is the Swift version of the accessory "Done" button:
#IBOutlet weak var textView: UITextView!
// In viewDidLoad()
let toolbar = UIToolbar()
toolbar.bounds = CGRectMake(0, 0, 320, 50)
toolbar.sizeToFit()
toolbar.barStyle = UIBarStyle.Default
toolbar.items = [
UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.FlexibleSpace, target: nil, action: nil),
UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.Done, target: nil, action: "handleDone:")
]
self.textView.inputAccessoryView = toolbar
// -----------------
func handleDone(sender:UIButton) {
self.textView.resignFirstResponder()
}