UIMenuController showing wrong items - ios

When i touch a label UIMenuController appears with my custom list of items, and that works well. But when UIMenuController appear in a standard UISearchBar i see all my custom items there too. Why?
I need to show only standard (copy, paste) items for standard UISearchBar and custom items when i touch the label. Can you explain how should i do that?
UPDATE
What i did (not good solution):
If we have keyboard, that is searchbar, if we don't, that is label.
Flag, which mean which items list i will use
BOOL standardList;
Register for keyboard appear/disappear
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil];
}
-(void)viewWillDisappear:(BOOL)animated
{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
[super viewWillDisappear:animated];
}
-(void)keyboardWillShow:(id)sender
{
standardList = YES;
}
-(void)keyboardWillHide:(id)sender
{
standardList = NO;
}
And check flag, in next method:
- (BOOL) canPerformAction:(SEL)selector withSender:(id) sender
{
if (selector == #selector(copy:))
{
return YES;
}
if (!standardList)
{
if ((selector == #selector(makeCall:)) || (selector == #selector(createNewContact:)))
{
return YES;
}
}
return NO;
}
That work well, BUT: iPad keyboard have "hide keyboard" button, and keyboard can hide without [UISearchBar resingFirstResponder].
Even if i add next lines:
-(void)keyboardWillHide:(id)sender
{
standardList = NO;
[mySearchController setActive:NO];
}
that's still bad solution - i can't hide keyboard while searching and scroll search results.
Any suggestions?

One solution:
u can always reset the UIMenuItems after u customize UIMenuController.
addObserver of UIMenuControllerWillHideMenuNotification.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(willHideEditMenu:) name:UIMenuControllerWillHideMenuNotification object:nil];
then in the willHideEditMenu: function
-(void)willHideEditMenu:(NSNotification *)object
{
//any other thing u want to do.
[[UIMenuController shareMenuController] setMenuItems:nil];
}
this way, UIMenuController singleton in other places won't get affected by what u have done where u customize it.
Other solution:
i think the root reason why u have this problem is u have some function with the same name of "makeCall:" or "createNewContact:" in other view or viewcontroller (basically may in any UIResponder) that is the parent view (viewcontroler) of the place where u have this problem.
so check out the responder tree, see if u can find any selectors with the same name of the UIMenuItem selectors. since
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender;
is a function of any UIResponder, it could get called. and if it does happen to have a selector with the same name, it could return YES, and u will have this problem. To solve the problem, just rename the selector of the UIMenuItem.
My English isn't good. Hope u get my point and try it.

Related

iOS: listener of the "hide" button in the keyboard

I'm using the
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField
to remove the keyboard when the user click on the return or done button and it works perfectly. My problem is that when my application is in the landscape mode or when I run it in the iPad, the "hide" button is added in the keyboard (the button displayed in the picture). When I click it, the keyboard is hided but the textFieldShouldReturn is never called.
How can I detect when this button is tapped?
Receiving Keyboard Notifications
When the keyboard is shown or hidden, iOS sends out the following notifications to any registered observers:
UIKeyboardWillShowNotification
UIKeyboardDidShowNotification
UIKeyboardWillHideNotification
UIKeyboardDidHideNotification
you can get the detail information from Apple document
for e.g
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardhideHandle:)
name:UIKeyboardWillHideNotification
object:nil];
- (void) keyboardhideHandle:(NSNotification *)notification {
NSLog(#"you received the action here");
}
To detect when the keyboard from a UITextField is being brought up we could setup the observers in viewDidLoad, like this for example:
- (void)viewDidLoad {
[super viewDidLoad];
// setup keyboard observers
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(keyboardCameUp:) name:UIKeyboardWillShowNotification object:nil];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(keyboardWentAway:) name:UIKeyboardWillHideNotification object:nil];
}
These observers will call a method in our class (using #selector). Mine are called keyboardCameUp and keyboardWentAway:
- (void)keyboardCameUp:(NSNotification *)notification {
NSLog(#"Keyboard came up!");
}
- (void)keyboardWentAway:(NSNotification *)notification {
NSLog(#"Keyboard went away!");
}
src: e.g. http://pinkstone.co.uk

Populate data in textfield from button action of another class

my problem is that i have a textfield on my viewcontroller which should be get filled by user and to provide options to fill the textfiled there is a arrow button front of textfield. Clicking on it open a new viewcontroller with a list of options. So when the user click on any option from that viewcontroller the data will automatically fill in that textfield and user return on previous viewcontroller. And i can not use preprefor segue in it so please provide an answer. If i am missing something let me know i ll comment or edit.
You can use NSNotificationCenter to fill back your UITextField. Add Observer to your first viewController class where you want to fill the textField. Add this lines of code in viewDidLoad-
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(fillMyTextField:) name:#"fillMyTextField" object:nil];
than add selector method in same class--
- (void)fillMyTextField:(NSNotification *)notification
{
self.myTxtField.text = (NSString *)notification.userInfo;
}
Now in your other viewController class where you select data for textField. Write the below code in method where you select your data like-
- (IBAction)selectDataAndBackToPreviosVC:(UIButton*)selectedOptionBtn {
id object=[NSString stringWithFormat:#"%#",selectedOptionBtn.titleLabel.text];
[[NSNotificationCenter defaultCenter] postNotificationName:#"fillTextField" object:nil userInfo:object];
[self.navigationController popViewControllerAnimated:YES];
}
in this I have used navigationViewController which use Push and Pop viewControllers and i have some UIButton in option selection viewController. I'm passing button title which is options to myTextField on IBAction.
In class where textfield Define Below method (add notification observer)
in viewDidLoad
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(fillTextField:)
name:#"fillTextField"
object:nil];
- (IBAction)fillTextField:(NSNotification *)sender
{
textField.text = (NSString *)notification.object
}
In Another class where u select date set below method in date selection action
[[NSNotificationCenter defaultCenter] postNotificationName:#"fillTextField" object:nil userInfo:textFieldInfo];
You can use NSNotification:
In View controller ofTextField add this
- (void) viewDidLoad
{
//Your rest of code then below statement
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(receiveTextNotification:)
name:#"TestNotification"
object:nil];
}
- (void)receiveTextNotification:(NSNotification *)notification {
NSLog(#"%# updated", [notification userInfo]);
}
- (void) dealloc
{
// If you don't remove yourself as an observer, the Notification Center
// will continue to try and send notification objects to the deallocated
// object.
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
In View controller of Button, on button click add this:
- (IBAction)fillTextFieldAction: (id) sender {
// All instances observing the `TestNotification` will be notified
[[NSNotificationCenter defaultCenter] postNotificationName:#"TestNotification" object:self userInfo:text]; //Object here can be any changed value .
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(fillTextFieldAction:) name:#"fillTextField" object:nil];
- (IBAction)fillTextFieldAction:(NSNotification *)notification
{
textField.text = (NSString *)notification.object
}
[[NSNotificationCenter defaultCenter] postNotificationName:#"fillTextField" object:nil userInfo:textFieldInfo];

Is it possible to get textfield assosiated with a keyboard?

In my view controller I'm subscribed to UIKeyboardWillShowNotification:
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(keyboardWillShow:)
name:UIKeyboardWillShowNotification
object:nil];
so in my keyboardWillShow: method I'm able to retrieve some info about the keyboard from the notification. But what I want is to get the reference to the actual text field which brings the keyboard up. I couldn't find how to do that in google and I suspect it might be impossible, but someone might know. If it is indeed impossible then I would like to know if there's a possibility to make it reverse way - to get the info about the keyboard by having the reference to the text field. Thanks
Let me emphasize that #iphonic comment is the right way to go.
You should use UITextField delegate function textFieldShouldBeginEditing:
Anything short of that is a kludge: UIKeyboardWillShowNotification assumes the software keyboard will show up, with is a very dangerous assumption and is likely to fail in all sorts of situations, starting with but not limited to Bluetooth keyboards. Try cmd-K in Simulator.
Here is aforementioned kludge, inspired by Get the current first responder without using a private API
func keyboardWillShow() {
let firstResponder = self.findFirstResponder(inView: self.view)
println("keyboardWillShow for \(firstResponder)")
}
func findFirstResponder(inView view: UIView) -> UIView? {
for subView in view.subviews as! [UIView] {
if subView.isFirstResponder() {
return subView
}
if let recursiveSubView = self.findFirstResponder(inView: subView) {
return recursiveSubView
}
}
return nil
}
There is one manual way
if ([firstName isFirstResponder]) {
// caused due to firstName
} else if ([lastName isFirstResponder]) {
// caused due to lastName
}
Swift
if firstName.isFirstResponder { // caused due to firstName }
else
if lastName.isFirstResponder { // caused due to lastName }
The easiest (and almost only) way to do this happens to also be the best way (as #iphonic mentioned)
Implement the UITextFieldDelegate delegate method textFieldShouldBeginEditing:textField
This method will be called before any other event (including any keyboard notifications)
Store the UITextField that received this delegate call to be referenced when determining which field triggered this event.
What I also recommend doing is, if you are looking to determine which keyboard fired the current keyboard appearance, within this delegate method simply register for receiving keyboard notifications.
- (BOOL)textFieldShouldBeginEditing:(UITextView *)textView {
[NSNotificationCenter.defaultCenter addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
return YES;
}
This way, you can be certain that when keyboardWillShow: is called, it was in fact triggered from this specific text field.
Of course, to make sure you keep track of your text fields correctly, stop listening when the text field stops editing.
- (void)textFieldDidEndEditing:(UITextView *)textView {
[NSNotificationCenter.defaultCenter removeObserver:self name:UIKeyboardWillShowNotification object:nil];
}
There is much better way to do this via did begin editing notifications of UITextField and UITextView:
UITextFieldTextDidBeginEditingNotification
and
UITextViewTextDidBeginEditingNotification
- (void)startListeningForKeyboardNotification {
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(responderDidBeginEditing:) name:UITextFieldTextDidBeginEditingNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(responderDidBeginEditing:) name:UITextViewTextDidBeginEditingNotification object:nil];
}
- (void)responderDidBeginEditing:(NSNotification *)notification {
if ([notification.object isKindOfClass:[UITextField class]]) {
UITextField *textField = notification.object;
// Do something with text field
} else if ([notification.object isKindOfClass:[UITextView class]]) {
UITextView *textView = notification.object;
// Do something with text view
}
}

Showing a hidden button

Please bear with me, as I am still learning the ropes of objective c.
I currently have a button that when pressed hides the iOS keyboard. I was wondering how I could do the opposite of this. When a text field is selected, the keyboard automatically appears- at the same time, I'd like this button to also appear on screen.
Thanks!
-(IBAction)done:(id)sender{
//...
//...
[Screen resignFirstResponder];
done.hidden = YES;
};
You will have to use NSNotification. Implement the addObserver in viewWillAppear and removeObserver in viewWillDisappear
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
}
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
}
-(void)keyboardWillShow:(NSNotification*)notification{
done.hidden = NO;
}
register for the UIKeyboardWillShowNotification like this:
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
and show the button in the method provided:
-(void) keyboardWillShow:(NSNotification*)notification{
done.hidden = NO;
}
do not forget to remove the observer in dealloc with
[[NSNotificationCenter defaultCenter] removeObserver:self];
You can use UITextFieldDelegate method to achieve this for example:
-(BOOL)textFieldShouldBeginEditing:(UITextField *)textField
{
done.hidden = NO;
return YES;
}
Hope it will help.

UIKeyboardWillShowNotification from custom class issue

I have a customized UITableViewCell with textfields. The textfields of the cells are set to call for delegate functions.
Inside
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillShowNotification
object:nil];
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIKeyboardWillHideNotification
object:nil];
if(textField == fromTF){
fromTF.text = [[[fromTF.text substringToIndex:2] stringByAppendingString:#":"] stringByAppendingString:[fromTF.text substringFromIndex:2]];
[toTF becomeFirstResponder];
return YES;
}
if(textField == toTF){
[toTF resignFirstResponder];
[intTF becomeFirstResponder];
return YES;
}
return YES;
}
This is delegate method is called in my custom cell.However when called, the UIKeyBoardWillHideNotification addobserver object is not removed when pressed 'return' key. Is there a way I can resolve this?
Try like this
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillHideNotification object:nil];
}
and also check this link textFieldShouldBeginEditing + UIKeyboardWillShowNotification + OS 3.2
it may help you.
Hello Ganesh thank you for the answer. I removed the resignFirstResponder and passed the firstResponder directly to the next textfield. This prevented the keyboard from disappearing.

Resources