I'd like to create an NSMenu containing an NSMenuItem which is hidden by default, and only appears while the user is holding a keyboard modifier key.
Basically, I'm looking for the same behaviour as the 'Library' option in the Finder's 'Go' Menu:
Without holding Option (⌥):
While holding Option (⌥):
I already tried installing a key listener using [NSEvent addGlobalMonitorForEventsMatchingMask: handler:] to hide and unhide the NSMenuItem programmatically by setting it's hidden property. This kind of worked, but the problem is that the hiding/unhiding wouldn't work while the NSMenu was open. Apparently an NSMenu completely takes over the event processing loop while it's open, preventing the key listener from working.
I could probably use a CGEventTap to still receive events while the NSMenu is open, but that seems like complete overkill.
Another thing I discovered which does a similar thing to what I want is the 'alternate' mechanism of NSMenu. But I could only get it to switch out NSMenuItems, not hide/unhide them.
Any help would be greatly appreciated. Thanks!
Let's say your option-only menu item's action is (in Swift) performOptionOnlyMenuItem(_:) and its target is your AppDelegate.
The first thing you need to do is make sure AppDelegate conforms to the NSMenuItemValidation protocol.
The second thing you need to do is implement the validateMenuItem(_:) method, and have it check whether the menu item sends the performOptionOnlyMenuItem(_:) action. If so, set the item's isHidden property based on whether the option key is currently pressed.
If you don't need to validate any other menu items, the code can look like this:
extension AppDelegate: NSMenuItemValidation {
func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
switch menuItem.action {
case #selector(performOptionOnlyMenuItem(_:)):
let flags = NSApp.currentEvent?.modifierFlags ?? []
menuItem.isHidden = !flags.contains(.option)
return true
default:
return true
}
}
}
If the action is sent to some other target, you need to implement the validation (including the protocol conformance) on that target. Each menu item is validated only by the item's target.
I found a solution that behaves perfectly!
On the NSMenuItem you want hidable, set the alternate property to YES, and set the keyEquivalentModifierMask property to the keyboard modifiers which you want to unhide the item.
In your NSMenu, right before the NSMenuItem which you want to be hideable, insert another NSMenuItem that has height 0.
In Objc, you can create an NSMenuItem with height 0 like this:
NSMenuItem *i = [[NSMenuItem alloc] init];
i.view = [[NSView alloc] initWithFrame:NSZeroRect];
The hideable NSMenuItem will now be 'alternate' to the zero-height NSMenuItem preceding it. The zero-height item will display by default, but while you hold the keyboard modifier(s) you specified, the zero-height item will be swapped out with the hideable item. Because the zero-height item is invisible, this has the effect of unhiding the hideable item.
I have an iPad app (XCode 6.1, iOS 8.1.1, ARC and Storyboards). In one of the classes (scene) I have this code:
-(BOOL) textFieldShouldBeginEditing:(UITextField *)textField { // (prevents keyboard from showing)
if(textField.tag == 200) { // birthdate
[self showModalCalendar:(int)textField.tag];
return NO; // don't show k/b
}
else
return YES;
}
It is executed when the first textField is selected, going through each textField rather than wait until each textField is selected. This is a problem because what I want to accomplish is to show the modal calendar only when a particular UITextField (birthdate) has been selected, and NOT show the keyboard. What's happening is when I tap the tab key (on a hard keyboard) the modal calendar also apprears for each textField.
Is there any way to prevent this?
The problem in my case was IQKeyboardManager library. I removed this library from my project and DownPicker works fine.
Rather than using tags you should create an IBOutlet to the particular textView that you want to handle. Then you can test if textView == your special one in the delegate callback.
The reason is that it is more explicit and clearer than using tags. My guess is that some of your other text views have that same tag for some reason and so your conditional isn't behaving as you think it should.
I have a simple uicollectionviewcell with some buttons and a uitextfield. Tapping the uitextfield pops the keyboard but my Done button makes the keyboard 'blink' and then the uppercase arrows fill in. Weird.
None of my uitextfield methods are called (I have them logged). The uitextfield is in the nib file and I tried setting delegate in code and in IB. Neither work but doing it in IB causes a crash with no info other than ldb.
I also have the Return key set to Done.
Any solutions?
Turns out I was dragging the delegate to the files owner - it needed to be dragged to the cells view. Solved.
I put a textfield in a window, and I want the textfield draw background only when focused.
I know that all the controls in the window share one field editor.
I tried subclass nstextfield and implement becomeFirstResponder and resignFirstResponder.
And tried use custom singleton editor for the window .
Any one know how to achieve this?
In the NSWindow ,every textfield or button share one instance of field editor(a singleton NSTextView instance),so when you click the textfield, textfield become firstResponser first,and then quickly pass it to the shared field editor. So when the textfield lost focus ,the resignFirstResponder of the textfield will never be called(because the field editor is the FirstResponder now).
You can look at fieldEditor:forObject: in NSWindow API.
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/ApplicationKit/Classes/NSWindow_Class/Reference/Reference.html#//apple_ref/occ/instm/NSWindow/fieldEditor:forObject:
SOLUTION:
(Thanks , Michael Gorbach)
In my window controller
- (id)windowWillReturnFieldEditor:(NSWindow *)sender toObject:(id)anObject
{
NSText *text = [sender fieldEditor:YES forObject:self];
if(text&&[anObject isKindOfClass:[MyCustomTextField class]])
{
[text setBackgroundColor:[NSColor whiteColor]];
[text setDrawsBackground:YES];
}
return text;
}
I just did this recently, in a tableView. You need to use a custom cell and fieldEditor. Specifically, you need to call setDrawsbackground:YES on the NSText/NSTextView object that is the field editor, and setBackground: to configure your color of choice. There are two places to set up a custom field editor.
One is to implement setUpFieldEditorAttributes: on a custom NSTextFieldCell subclass that you have configured your NSTextField to use, and another is to use the window or window delegate method windowWillReturnFieldEditor:toObject:.
Note that if the first method doesn't work for a particular setting, sometimes you need to use the second, because it gets in earlier in the codepath.
I have a view with a UITextField which should hide the keyboard when return is pressed.
My function is this:
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
if ( textField == userPassword ) {
[textField resignFirstResponder];
}
return YES;
}
Normally the keyboard should be hidden but it stays on the screen. resignFirstResponder is correctly called. What am I missing?
I see you have the iPad tag on this. Do you happen to be presenting a modal view using UIModalPresentationFormSheet? If so, it looks like this is a limitation of the FormSheet modal presentation (either Apple is doing it intentionally for some reason, or it is a bug). See these other questions for more details:
Modal Dialog Does Not Dismiss Keyboard
Modal View Controller with keyboard on landscape iPad changes location when dismissed
There is this helpful method which allows you to dismiss the keyboard when presenting the Modal Dialog:
- (BOOL)disablesAutomaticKeyboardDismissal { return NO; }
This will override the default behavior of the modal dialog set by Apple and allow you dismiss the keyboard. It is in the UIViewController Class.
I hope this helps someone!
If you are using the Interface Builder, look if your UITextField has the delegated linked with your class.
-Select your UITextField and in your Connections look if exits one connection in Outlets->delegate. If not, conect with you File's Owner Class.
This need to be linked with your File's Owner Class. This delegate tell where to search for a method. If your are overriding a method, you need to tell where the object will search for that.
This solution worked for me after none of the above did. after calling resignFirstResponder i added a modal view & removed it.
[myTextField resignFirstResponder];
UIViewController *dummyController = [[UIViewController alloc] init];
UIView *dummy = [[UIView alloc] initWithFrame:CGRectMake(-1, -1,1,1)];
[dummyController setView:dummy];
[self presentModalViewController:dummyController animated:NO];
[dummyController dismissModalViewControllerAnimated:NO];
To deal with the bug mentioned by Brandon, you can try closing and re-opening your modal view controller as long as you still have a reference to it.
[textField resignFirstResponder];
[self dismissModalViewControllerAnimated:NO];
[self presentModalViewController:yourModalViewControllerReference animated:NO];
(where "self" should be the controller you used to originally open the modal view controller)
I was having the same problem. I realized that after connecting the delegate to the File's Owner in Interface Builder, I neglected to save in Interface Builder. Once I saved, I recompiled and the keyboard disappears correctly when hitting return.
xcode 4.5.1
Simply click control then on the textfield drag and release on the .h file
(control key+ drag)
then in the pop up menu select
connection=acton;
name= any name;
type=id;
event=did end on exit;
arguments=sender;
then click connect button
Did you remember to implement the UITextFieldDelegate protocol?
I have read so many articles about this issue, where the onscreen keyboard refuses to hide when you call resignFirstResponder, but none of the suggestions worked for me.
I'm using XCode 5 (iOS 7) and have a iPhone screen containing a couple of controls which require the onscreen keyboard, but if the user clicks on the UIButton, then I want the keyboard to disappear.
I probably wasted one full day experimenting with resignFirstResponder and adding disablesAutomaticKeyboardDismissal functions to return NO, but nothing worked. Once the onscreen keyboard appeared, I could never get it to disappear again.
But then I had a small brainwave (as I only have a small brain).
Now, when the user clicks on my UIButton, I simply disable the UITextField and UITextView controls.
- (IBAction)btnDate_Tapped:(id)sender {
// The user has clicked on the "Date" button.
self.tbClientName.enabled = NO;
self.tbComments.editable = NO;
And suddenly, the app finds it has no editable text fields needing an onscreen keyboard, and it neatly slides the keyboard out of sight.
(Relieved sigh.)
My UIButton actually makes a popup dialog appear. When the user dismisses the popup, I re-enable these two controls, so if the user taps in one of them, the keyboard will appear again.
-(void)popoverControllerDidDismissPopover:(UIPopoverController *) popoverController {
// The user has closed our popup dialog.
// We need to make our UITextField and UITextView editable again.
self.tbClientName.enabled = YES;
self.tbComments.editable = YES;
... etc...
}
Simple, isn't it !
And surprisingly, this workaround even works on UIViewControllers which appear in Modal style.
I hope this helps other XCode victims out there.
Based on your comment that it looks like focus has shifted, then I think what may be happening is that the keyboard is staying open for the next text input field. If your return key is a "Next" key, then returning YES for textFieldShouldReturn: will make the next textField the first responder, and keep the keyboard visible.
The easiest way is:
Go to your user interface builder,
select UITextField and "Control-Drag" to "Detail View Controller-Detail" and release.
The window will pop-up. Then under "Outlets" select "Delegate".
That's it. It worked for me.
if you are in UIModalPresentationFormSheet just call
- (BOOL)disablesAutomaticKeyboardDismissal
{
return NO;
}
Swift 3.0:
override var disablesAutomaticKeyboardDismissal: Bool {
get{
return false
}
set {
self.disablesAutomaticKeyboardDismissal = false
}
}
Swift 3.0
func textFieldShouldBeginEditing(_ textField: UITextField) -> Bool {
if textField == addressTextField {
textField.resignFirstResponder()
return false
}
return true
}