On the UISearchBar, there's an X element that allows you to clear all of the contents at once. Is there a way to get notified when this happens?
UISearchBarDelegate::searchBarCancelButtonClicked is fired only when the "Cancel" button is tapped.
The UISearchBar doesn't have a delegate method for this event. You can nearly get what you want by implementing the textDidChange: method of the callback delegate and checking for an empty string.
I don't recommend it, but there is another possible way. The UISearchBar is composed of a UITextField, which does have a delegate method that is called when the user taps the clear button (textFieldShouldClear:). You can get the UITextField by traversing the UISearchBar's child views:
(this is in the context of a derived UISearchBar class)
- (UIView*) textField
{
for (UIView* v in self.subviews)
{
if ( [v isKindOfClass: [UITextField class]] )
return v;
}
return nil;
}
from here, you could re-assign the UITextField delegate to your own implementation, taking care to forward delegate calls to the old delegate. This way you could intercept textFieldShouldClear:. Or if it turns out the UISearchBar is the delegate for the UITextField it contains you could swizzle the call to textFieldShouldClear:... Not ideal, clearly, but technically feasible.
I had the same issue and I solved this issue by using this function.
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
// This method has been called when u enter some text on search or Cancel the search.
if([searchText isEqualToString:#""] || searchText==nil) {
// Nothing to search, empty result.
[UIView animateWithDuration:0.2 animations:^ {
//Reposition search bar
[_searchBar setFrame:CGRectMake(230, 26, 43, 44)];
[_searchBar setNeedsLayout];
}];
}
}
Here is an answer from a previous question, this should do exactly what you want. UISearchbar clearButton forces the keyboard to appear
Here is "Method Swizzling" solution.
Create a new Category of UISearchBar. This category create a new method and swizzle method between -(BOOL)textFieldShouldClear:(UITextField *)textField; and -(BOOL)jbm_textFieldShouldClear:(UITextField *)textField in runtime.
Customize a new Protocol of UISearchBarDelegate in order to add a new method - (void)searchBarClearButtonClicked:(id)sender;
UISearchBar+JMBTextFieldControl.h
#protocol UISearchBarWithClearButtonDelegate <UISearchBarDelegate>
#optional
- (void)searchBarClearButtonClicked:(id)sender;
#end
#interface UISearchBar (JMBTextFieldControl)
#end
UISearchBar+JMBTextFieldControl.m
#import "UISearchBar+JMBTextFieldControl.h"
#import <objc/runtime.h>
#implementation NSObject (Swizzling)
+ (void)brc_swizzleMethod:(SEL)origSelector withMethod:(SEL)newSelector
{
Method origMethod = class_getInstanceMethod(self, origSelector);
Method newMethod = class_getInstanceMethod(self, newSelector);
if(class_addMethod(self, origSelector, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)))
class_replaceMethod(self, newSelector, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
else
method_exchangeImplementations(origMethod, newMethod);
}
#end
#implementation UISearchBar (JMBTextFieldControl)
+ (void)load {
[self brc_swizzleMethod:#selector(textFieldShouldClear:) withMethod:#selector(jbm_textFieldShouldClear:)];
}
- (id<UISearchBarWithClearButtonDelegate>)jbm_customDelegate {
if( [[self delegate] conformsToProtocol:#protocol(UISearchBarWithClearButtonDelegate)] )
return (id<UISearchBarWithClearButtonDelegate>)[self delegate];
else
return nil;
}
- (BOOL)jbm_textFieldShouldClear:(UITextField *)textField
{
if ( [[self jbm_customDelegate] respondsToSelector:#selector(searchBarClearButtonClicked:)] )
[[self jbm_customDelegate] searchBarClearButtonClicked:self];
return [self jbm_textFieldShouldClear:textField];
}
#end
Reference
Dave DeLong -
How to add a method to an existing protocol in Cocoa?
Nikolay Vlasov - CCBottomRefreshControl
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
i'm working on an app which has a tableView with a textField in the right side of its each cell(there are more than 20 cells).
i've created custom cell's for each row except for the last one.
In the last row there is only a button.
Now i want to call resignFirstResponder on the button's click.
What should i do Please help?
You will have to keep track of which textfield in which cell has the first responder and resign it like this.
[myCellTextField resignFirstResponder];
You probably want to keep track of the text field with the keyboard. Implement the <UITextFieldDelegate> protocol in your controller, and set the controller as each of the text fields' delegates. Write the textFieldDidBeginEditing: method like so, setting an instance variable called currentTextField:
- (void)textFieldDidBeginEditing:(UITextField *)textField {
currentTextField = [textField retain];
}
Then, in your action for the button run [currentTextField resignFirstResponder].
Aopsfan's answer is probably the best solution so far. However, to add to it (as I cannot post comments), do remember to deallocate the object:
- (void)textFieldDidBeginEditing:(UITextField *)textField {
if (currentTextField != nil) {
[currentTextField release];
}
currentTextField = [textField retain];
}
Better still use #property's and #synthesize so the runtime can do the memory management for you.
[ViewController].h
#property (nonatomic, retain) UITextField* currentTextField;
[ViewController].m
#synthesize currentTextField = _currentTextField;
- (void)viewDidLoad|Appear {
self.currentTextField = nil;
}
- (void) dealloc {
[_currentTextField release], _currentTextField = nil;
...
[super dealloc];
}
- (void)textFieldDidBeginEditing:(UITextField *)textField {
self.currentTextField = textField;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (self.currentTextField) {
[self.currentTextField resignFirstResponder];
}
}
I think this link will help you:
Objective C: ResignFirstResponder with a button
Provide some code so that, it will be easier to help u.
Hope this helps you. :)
I am trying to use textFieldShouldBeginEditing to disable the keyboard from showing up for a custom UITextField. I'm implementing all the UITextFieldDelegate methods. However, for some reason, textFieldShouldBeginEditing actually never gets called.
The following delegate methods ALWAYS get called:
– textFieldDidBeginEditing:
– textFieldShouldEndEditing:
– textFieldDidEndEditing:
The view is structured in the following way:
UIViewController which holds a scrollview. Depending on the state of the view, this ScrollView will contain a UIView with a list of custom UITextFields.
I'm running iOS 4.3.5 (8L1) on this device.
Any ideas?
Edit; added some code snippets:
UIViewController has the following interface
#interface AViewController: UIViewController<UITextFieldDelegate>
Once the UIViewController loads, I connect all UITextFields to the view using
aSubView.aTextField.delegate = self;
(Simplified) delegate implementations located in AViewController
- (void)textFieldDidBeginEditing:(UITextField *)textField
{
}
- (void)textFieldDidEndEditing:(UITextField *)textField
{
}
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
return YES;
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
{
return YES;
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
return YES;
}
Custom UITextField code
Simplified implementation file --
#import "PVEntryTextField.h"
#import "EntryViewController.h"
#implementation PVEntryTextField
#synthesize isPasswordField, state, singleTap;
- (id)initWithCoder:(NSCoder *)inCoder
{
if (self = [super initWithCoder:inCoder])
{
self.font = [UIFont fontWithName:#"Helvetica-Bold" size:19];
self.textColor = [UIColor colorWithRed:51.0/255.0
green:51.0/255.0
blue:51.0/255.0
alpha:1.0];
self.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
}
return self;
}
- (CGRect)textRectForBounds:(CGRect)bounds
{
return CGRectMake(bounds.origin.x + 16, bounds.origin.y,
bounds.size.width - 16*2 - 10, bounds.size.height);
}
- (CGRect) editingRectForBounds:(CGRect)bounds
{
return [self textRectForBounds:bounds];
}
- (BOOL) canBecomeFirstResponder
{
return YES;
}
- (void) updateState:(int) newState
{
state = newState;
}
- (void)dealloc
{
[super dealloc];
}
#end
Is it posible that textFieldShouldBeginEditing is called by the default implementation of the method canBecomeFirstResponder?
Try implementing the method by [super canBecomeFirstResponder] or just removing it.
Have you set the UITextField delegate to "self"?
For anyone that comes here and didn't find a solution. My problem was that I created the textField in IB and then alloc one in my viewDidLoad. When I removed the instantiation, the delegate worked correctly as it was tied to the correct TF.
//I REMOVED these two lines because I created the textfield in IB
_nameTextField = [[UITextField alloc] init];
_priceTextField = [[UITextField alloc] init];
[_nameTextField setDelegate:self];
[_priceTextField setDelegate:self];
I also ran into the issue of not having textFieldShouldEndEditing or textFieldShouldReturn called. This occurred after updating my app's Storyboard.
The delegate methods were getting called when the UITextFields where part of the ViewController subclass.
But, when they were moved into a Scroll View within the ViewController, the methods were no longer called.
Setting their app delegates to self in ViewDidLoad fixed this problem.
self.emailField.delegate = self;
self.passwordField.delegate = self;
In Swift-3 following method required "_" before textField so that this delegate method will call. In my case it helps me.
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
}
Dont know if is a typo error on copying the code here but the method name is incorrect:
CORRECT - textFieldShouldBeginEditing
YOURS - textFieldShoulBeginEditing (missing "d")
I m using -(void)textFieldDidBeginEditing:(UITextField *)sender this function in my application. this is not called when i select the textfield.
here's the code...
-(void)textFieldDidBeginEditing:(UITextField *)sender{
if([sender isEqual:txtName])//txtName is the IBOutlet of the UITextField
{
NSLog(#"Name");
}
else{
NSLog(#"NO_Name");
}
}
Did you set delegate of UITextField's instance to current view controller like this:
textField.delegate = self; (self means the instance where callback textFieldDidBeginEditing is overridden)
Make sure to complete 2 simple steps
1 - Implement the delegate UITextFieldDelegate
#interface yourViewController : UIViewController <UITextFieldDelegate>
2 - Set the delegate
yourTextField.delegate = self
If you have many text fields in your view, you can set delegate for all of your text fields like this
for (id subView in self.view.subviews)
{
if ([subView isKindOfClass:[UITextField class]]) {
[subView setDelegate:self];
}
}
You must include UITextFieldDelegate in .h file
#interface yourViewController : UIViewController <UITextFieldDelegate>
You must include UITextFieldDelegate in your .h file, and also add YourTextField.delegate = self
Is possible to know when the user touch the keyboard iphone? When the user touch some button from keyboard... :/
The easiest way is to use a TextField. Even is your UI Does not call for one, you can set it's frame to zero so it doesnt show up onscreen. Then you can get access to the keys pressed by using the text field's delegate callback methods.
- (void)viewDidLoad {
[super viewDidLoad];
//CGRectZero because we don't want the textfield to be shown onscreen
UITextField *f = [[UITextField alloc] initWithFrame:CGRectZero];
//We set the delegate so we can grab keypressed
f.delegate = self;
[self.view addSubview:f];
[f becomeFirstResponder]; //Show the keyboard
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)string {
if (string.length >0) {
NSLog(#"%# Pressed",string);
}
else {
NSLog(#"Backspcae pressed");
}
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
NSLog(#"return pressed");
return YES;
}
Note: to avoid a compiler warning, make sure in your .h file the class explicitly says it implements the UITextFieldDelegate protocal. ie:
#interface MyViewController : UIViewController <UITextFieldDelegate>