UITextViewDelegate methods not being called (UITextView within UITableViewCell) - iphone

I must be doing something fundamentally wrong, my implementation methods for the UITextViewDelegate aren't firing. I have a UITextView that is a subview of a UITableCellView and the delegates aren't being called.
- (void)textViewDidBeginEditing:(UITextView *)textView {
NSLog(#"textViewDidBeginEditing");
// never called...
}
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
NSLog(#"shouldChangeTextInRange");
// never called...
}
Suggestions? I don't know whether it matters, but the protocol is explicitly named in my #interface declaration.
#interface DetailViewController () <UITextViewDelgate, ..., ....>
Thanks!

You should add the textViewObj.delegate = self or give delegate connection for that text view property in xib file, then it should work and fire all delegate methods of UITextView.

Couple of pointers on this based on my experience:
1) Check whether you are using a UITextField or a UITextView.
2) Based on the type of text field you are using add the following declaration to your interface declaration
#interface MyInterface : UIViewController<UITextFieldDelegate>
or
#interface MyInterface : UIViewController<UITextViewDelegate>
3)Register your controller as the delegate for your text field:
[myTextField setDelegate:self];
4)Override the desired method which being
-(void)textFieldDidBeginEditing:(UITextField *)textField
or
- (void)textViewDidBeginEditing:(UITextView *)textView;
in my case.

Related

Textfield event is never called in delegate

In my interface I have:
#interface MainViewController : UIViewController <SKProductsRequestDelegate, SKPaymentTransactionObserver, UITextFieldDelegate> {
UITextField *Stock;
// ....
}
This is the implementation I have:
- (BOOL)Stock:(UITextField *)textField shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
if([[textField text] isEqualToString:#"\n"]) {
[textField resignFirstResponder];
return NO;
}
return YES;
}
In the viewDidLoad I have Stock.delegate = self;
I am expecting this method is called after any character is typed in the text field. But this routine is never called. What is the problem?
Thanks
If this is a UITextField, you've just implemented a random method. The actual delegate method is
-textField:shouldChangeCharactersInRange:replacementString:
Try providing that one.
Did you wire the TextField (Stock in your case) Delegate to FileOwner ?
If not then try this in viewDidLoad method of the Controller
Stock.delegate = self;
Or you can just wire it in IB.
Declare MainViewController conforming UITextFieldDelegate:
#interface MainViewController : UIViewController < UITextFieldDelegate >
To be called this method of UITextFieldDelegate should be declared as:
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
In code or in IB MainViewController should be set to be delegate.
Correct and it will be fired as supposed.

-(void)textFieldDidBeginEditing:(UITextField *)sender.. this function is not called when i select textfield?

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

How to make UITextView "Done" button resignFirstResponder?

I am trying to make my editable UITextView resign the keyboard (resignFirstResponder) when the user taps "Done." Using a UITextField, I have been able to do this with the following code:
- (IBAction)doneEditing:(id)sender {
[sender resignFirstResponder];
}
... and then to attach it to the relevant UITextField in Interface Builder to the action "Did End on Exit."
However, with a UITextView, I can't seem to access the "Did End on Exit" action. Any suggestions on how to make this happen?
The accepted answer didn't work for me. Instead, the following delegate method should be invoked like this:
- (BOOL) textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
if([text isEqualToString:#"\n"]){
[textView resignFirstResponder];
return NO;
}else{
return YES;
}
}
Paste that into the class that you assign to be the UITextView delegate and it'll work.
new Answer
On your View, you'd have a UIBarButton ("Done") that is connected to the IBAction below:
- (IBAction)doneEditing:(id)sender {
[textView resignFirstResponder];
}
Where textView is your textView outlet defined in your .h file and connected in Storyboard or .xib file. Like this:
#property (retain, nonatomic) IBOutlet UITextView *textView;
old Answer
Check the following:
Is UITextViewDelegate specified
in .h
Implement delegate method
for uitextview:
textViewShouldEndEditing, return YES
make sure your .m (controller) is the
delegate for uitextview in IB
resignFirstResponder should now
work.
You can implement UITextViewDelegate and wait for "\n", in Swift 4 :
myTextView.delegate = self
// ...
extension MyViewController : UITextViewDelegate {
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
if text == "\n" {
textView.resignFirstResponder()
return false
}
return true
}
}
To have the done button dismiss the keyboard and resignFirstResponder you have to implement a delegate method.
In your .h implement the UITextFieldDelegate
#interface YourViewController : UIViewController <UITextFieldDelegate>
Then implement the textFieldShouldReturn in your .m
-(BOOL) textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return YES;
}
Don't forget to link the delegate of UITextField to the file's Owner (very important)

UISearchBar and event fired when 'X' element is tapped

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

Insert date/time in UITextView when user hits return

Im trying to Insert the current date/time whenever the users hits the return key or starts typing on a UITextView in Xcode but not quite sure where to start.
I know this method is for when clicking into the TextView but doesn't seem to work:
- (void)textViewDidBeginEditing:(UITextView *)textView {
self.txtDetail.text = [self.txtDetail.text stringByAppendingString:#"Hello!"];
}
Thanks
Update:
DetailViewController.h
#interface DetailViewController : UIViewController <UIPopoverControllerDelegate, UISplitViewControllerDelegate> {
UITextView *txtDetail;
}
#property (nonatomic, retain) IBOutlet UITextView *txtDetail;
- (void)textViewDidBeginEditing:(UITextView *)textView;
DetailViewController.m
#synthesize txtDetail;
- (void)textViewDidBeginEditing:(UITextView *)textView {
NSLog(#"Hello");
self.txtDetail.text = [self.txtDetail.text stringByAppendingString:#"Hello!"];
}
Update02:
Ive added this to my .m files:
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
BOOL shouldChangeText = YES;
if ([text isEqualToString:#"\n"]) {
// Find the next entry field
txtDetail.text = [txtDetail.text stringByAppendingString:#"\nhey\n"]; }
textView.editable = YES;
shouldChangeText = NO;
[textView becomeFirstResponder];
return shouldChangeText;
}
I get the desired effect (Hey is added in whenever i press return on the keyboard) but i now can't type anything... any ideas?
You have to declare you controller as implementing the UITextViewDelegate Protocol and then connect it as the text view's delegate. Otherwise it never receives the delegate messages at all.
Then you have to implement:
– textView:shouldChangeTextInRange:replacementText:
... to return YES/TRUE otherwise no text gets added.
Update02:
You need to implement all the UITextViewDelegate protocol methods that have a return. If you don't, the text view assumes a NO by default.
See: Text and Web Programming Guide: Managing TextFields and TextViews
You also need to understand the Delegate Pattern.
Replace your method with the below method
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
{
BOOL shouldChangeText = YES;
if ([text isEqualToString:#"\n"] && textView == detailText)
{
// Find the next entry field
txtDetail.text = [txtDetail.text stringByAppendingString:#"\nhey\n"];
textView.editable = YES;
shouldChangeText = NO;
[textView becomeFirstResponder];
}
return shouldChangeText;
}
The mechanics of delegate calls is a very important part of iOS programming. There is a doc on it in the Apple libraries, and it is also discussed in many good books. The Apress book "Beginning iPhone Programming" is very good and covers delegate methods.