I'd like to create a text field which uses the number pad and accepts only numbers, even when pasted. Currently, I have a header as such:
#import <UIKit/UIKit.h>
#interface DRPNumberTextField : UITextField <UITextFieldDelegate>
#end
and an implementation:
#import "DRPNumberTextField.h"
#implementation DRPNumberTextField
- (id) initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
self.delegate = self;
[self setKeyboardType:UIKeyboardTypeNumberPad];
}
return self;
}
- (BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if ([string rangeOfCharacterFromSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]].location != NSNotFound)
{
return NO;
}
return YES;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
I've set the text fields to use this class in the storyboard. However, my desired functionality does not occur. Moreover, as determined by debugging, initWithFrame: is never called. Any ideas? As more context, these text fields are embedded inside table cells of a table view of a table view controller. Of these, I provide a custom implementation of the table view controller here:
#interface DRPImplementSettingsViewController ()
#end
#implementation DRPImplementSettingsViewController
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end
Thus it really has no implemented functionality beyond the stock. Its header is the obvious one.
EDIT: As some have pointed out, I don't need to subclass the text field to implement delegate functionality. I can put that elsewhere. But my question is this: why doesn't what I've presented here work? I can't find my mistake.
You need also override - (id)initWithCoder:(NSCoder *)decoder in your DRPNumberTextField. if you are using the custom UITextField in XIB or storyboard, initWithFrame: will not be called, initWithCoder: is called instead.
You can try with this also,
Its also works
DRPNumberTextField.m
#import "DRPNumberTextField.h"
#implementation DRPNumberTextField
- (void)awakeFromNib
{
[super awakeFromNib];
self.delegate = self;
[self setKeyboardType:UIKeyboardTypeNumberPad];
}
- (BOOL) textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
if ([string rangeOfCharacterFromSet:[[NSCharacterSet decimalDigitCharacterSet] invertedSet]].location != NSNotFound)
{
return NO;
}
return YES;
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect
{
// Drawing code
}
*/
#end
You don't need to subclass to do this, you can just implement theUITextFieldDelegate method textField:shouldChangeCharactersInRange:replacementString:. Every time the method is called check that the replacementString only contains characters you want to allow and return YES or NO depending on whether it does.
Here is an alternative to subclassing, rather subclassing you can use delegate method of textfield for that
check this,
-(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
#define NUMBERS #"0123456789"
#define NUMBERSPERIOD #"0123456789-"
NSCharacterSet *cs;
NSString *filtered;
// Period is in use
if (textField.tag==8)
{
cs = [[NSCharacterSet characterSetWithCharactersInString:NUMBERS] invertedSet];
filtered = [[string componentsSeparatedByCharactersInSet:cs] componentsJoinedByString:#""];
return [string isEqualToString:filtered];
}
return YES;
}
Set your textfield tag appropriate . It will also want past other character.
Related
I have a custom cell and in the custom cell, I have a textfield where user can able to change the value. No matter, what I tried, I cannot able to dismiss the keyboard when user enters some values. It does not hit any of the delegate methods shown below.
CheckOutTableViewCell.m
#import "CheckOutTableViewCell.h"
#implementation CheckOutTableViewCell
#synthesize productName;
#synthesize productPrice;
#synthesize productOrderNumberTF;
- (void)awakeFromNib {
[super awakeFromNib];
// Initialization code
}
-(id) init;
{
self = [super init];
if (!self) return nil;
productOrderNumberTF.delegate = (id)self;
return self;
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
// enter closes the keyboard
if ([string isEqualToString:#"\n"])
{
[textField resignFirstResponder];
return NO;
}
return YES;
}
- (void) textFieldDidEndEditing:(UITextField *)textField {
NSLog(#"%#", textField.text);
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
// dismiss keyboard when user clicks on anywhere on the UI
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self.productOrderNumberTF resignFirstResponder];
}
CheckOutTableViewController.m
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *cellIdentifier = #"cell";
CheckOutTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
cell = [[CheckOutTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier];
cell.productOrderNumberTF.delegate = (id)self;
}
return cell
}
Screenshot of the ViewController
Your delegate methods are not calling because of your textfield delegate value is not assigned.
Assign the delegate value inside the awakeFromNib
- (void)awakeFromNib {
[super awakeFromNib];
productOrderNumberTF.delegate = self;
}
The nib-loading infrastructure sends an awakeFromNib message to each object recreated from a nib archive, but only after all the objects in the archive have been loaded and initialized. When an object receives an awakeFromNib message, it is guaranteed to have all its outlet and action connections already established.
I am new in iOS and I am facing problem regarding to create Custom delegate of UITextField
My code is like this
In CustomTableView
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
if([self.delegate respondsToSelector:#selector(textFieldShouldEndEditing:)])
{
[self.delegate textFieldShouldEndEditing:textField];
}
return YES;
}
In View Controller
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
return YES;
}
But this method is not getting call in ViewController.
Can Any body please tell me what I am doing wrong
Thanks in Advance!
You should not call textField's delegates methods manually like [self.delegate textFieldShouldEndEditing:textField];
If you want to call your delegate method from another class then make some method which is not provided by sdk!
for example make method like,
- (BOOL)myTextFieldShouldEndEditing:(UITextField *)textField
{
return YES;
}
and call this method from your other class by your self.delegate and make sure that self.delegate is not nil, i mean it have object of your viewController!
you need to create a custom TextField class and also set delegate in that class. Like this
.h File
#interface CustomTextField : UITextField<UITextFieldDelegate>
#end
.m File
#implementation CustomTextField
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
self.delegate = self;
}
return self;
}
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField{
return YES;
}
- (void)textFieldDidBeginEditing:(UITextField *)textField{
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField{
return YES;
}
- (void)textFieldDidEndEditing:(UITextField *)textField{
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string{
return YES;
}
- (BOOL)textFieldShouldClear:(UITextField *)textField{
return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
return YES;
}
#end
I have outlet the connection of UITextField and written this code
-(void)viewDidLoad
{
[txtName addTarget:self action:#selector(textFieldDidChange:) forControlEvents:UIControlEventEditingChanged];
}
-(void)textFieldDidChange :(UITextField *)theTextField{
NSLog(#"Text changed");
}
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
if(textField==txtName)
{
[self.view endEditing:YES];
[self performSelector:#selector(ShowNames) withObject:nil afterDelay:0.1];
return NO;
}
return YES;
}
But -(void)textFieldDidChange :(UITextField *)theTextField{ is not fired
Couldn't understand where Am I going wrong
Any help would be appreciated
Replace the code method
-(void)textFieldDidChange :(UITextField *)theTextField{
NSLog(#"Text changed");
}
with
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
{
If you want to UITextField events you should use UITextFieldDelegate
In your .h file adopt UITextFieldDelegate
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController<UITextFieldDelegate>
and then in your .m file
- (void)viewDidLoad
{
[super viewDidLoad];
[_txtName setDelegate:self];
}
Let me know if you have any issues
You've got the right idea, but your problem is within your -(BOOL)textFieldShouldBeginEditing:(UITextField *)textField method.
Right now, before editing this method is called, and if the method returns NO, then the -(void)textFieldDidChange :(UITextField *)theTextField method will not be called.
Your if statement tests to see if the textField that should start editing is the same as txtName. If it does you are returning NO instead of YES. I think you just need to swap your NO's and YES's and you'll be golden.
Try this:
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
if(textField==txtName)
{
[self.view endEditing:YES];
[self performSelector:#selector(ShowNames) withObject:nil afterDelay:0.1];
return YES;
}
return NO;
}
I wrote a subclass of UITextView ,to make the textView auto grow or shrink with the textView's content . Now ,I have to the textView's delegate to the subclass object it self (because i have to do something in - (void)textViewDidChange:(UITextView *)textView)
#implementation AutoGrowTextViewV2
- (instancetype) initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self)
{
self.delegate = self;
}
return self;
}
- (CGSize)intrinsicContentSize
{
return [self sizeThatFits:CGSizeMake(self.bounds.size.width, MAXFLOAT)];
}
- (void)textViewDidChange:(UITextView *)textView
{
[self invalidateIntrinsicContentSize];
[self layoutIfNeeded];
}
But in practice , AutoGrowTextViewV2 always need to set it's delegate to other objects , so I had to write textViewDidChange codes in everywhere. how can i make this simple? maybe runtime forward or something?
so I've been trying to get this pickerview working but I just can't get it to work. When I run the app it crashes without any stacktrace and shows Thread 1: EXC_BAD_ACCESS on [textField becomeFirstResponder]. The pickerArray is correct, so that's not the problem.
#import "TestViewController.h"
#import "FindClasses.h"
#interface TestViewController ()
#property UIPickerView *picker;
#property NSArray *pickerArray;
#property (nonatomic, strong) FindClasses *finder;
#end
#implementation TestViewController
#synthesize finder = _finder;
- (FindClasses *)finder
{
if (!_finder) _finder = [[FindClasses alloc] init];
return _finder;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.pickerArray = [self.finder findClassesInTimetable];
self.classField.delegate = self;
self.picker = [[UIPickerView alloc] init];
self.picker.delegate = self;
self.picker.dataSource = self;
self.classField.inputView = self.picker;
// Do any additional setup after loading the view.
}
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
[textField becomeFirstResponder];
return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
return YES;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - UIPickerView method implementation
-(NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView{
return 1;
}
-(NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component{
return self.pickerArray.count;
}
-(NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component{
return [self.pickerArray objectAtIndex:row];
}
Thanks.
Try removing [textField becomeFirstResponder]; from the following method:
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
[textField becomeFirstResponder];
return YES;
}
The error is not relating to the picker field. The becomeFirstResponder is called automatically when the text field is selected. So there is no need for it to be called here as it would have already been called when you clicked the text field.
Basically your telling the text field that is active, to become active... Give it a go and let me know what the result is.
In relation to the picker view not showing up, make sure you have the IBOutlets connected up properly if using storyboards, also edit the following at the top of you .m file so it looks like the below:
Before:
#interface TestViewController ()
After:
#interface TestViewController () <UIPickerViewDataSource, UIPickerViewDataSource>
to have ur pickerview as your first responder, use
- (void)textFieldDidBeginEditing:(UITextField *)textField {
if([textField isEqual:classField]) {
[textField setInputView:picker]; //edited ones
[picker becomeFirstResponder];
}
}
use this method,
it will help you.
-(void)textFieldDidBeginEditing:(UITextField *)textField
{
if ([self.classField isEditing]) {
[self.picker selectRow:0 inComponent:0 animated:YES]; //This is not necessary but I prefer it for my purpose
[self.picker reloadAllComponents];
}
}
And Make sure your TextField Delegate is calling ... Means <UITextFieldDelegate> must be in your .h file like <UITextFieldDelegate, UIPickerViewDelegate, UIPickerViewDataSource>
Hope This Helps You...
If this doesn't work then Try this
self.picker = [[UIPickerView alloc]initWithFrame:CGRectZero];
[self.picker setDataSource:self];
[self.picker setDelegate:self];
[self.classField setInputView:self.picker]