Mountain Lion offers a built-in sharing button that reveals a menu of sharing services appropriate for the app:
How can I insert it in my app?
To add the share button on Mountain Lion:
1) Add a NSButton called, for example, shareButton.
2) Add the standard image for this button:
[shareButton setImage:[NSImage imageNamed:NSImageNameShareTemplate]];
[shareButton sendActionOn:NSLeftMouseDownMask];
3) Into the "on click action", present the NSSharingServicePicker:
NSSharingServicePicker *sharingServicePicker = [[NSSharingServicePicker alloc] initWithItems:urls];
sharingServicePicker.delegate = self;
[sharingServicePicker showRelativeToRect:[sender bounds]
ofView:sender
preferredEdge:NSMinYEdge];
4) Eventually, implement the NSSharingServicePickerDelegate methods to customize the picker’s available services.
In Swift, I've used this:
extension NSSharingService {
class func shareContent ( content: [AnyObject], button: NSButton ) {
let sharingServicePicker = NSSharingServicePicker (items: content )
sharingServicePicker.showRelativeToRect(button.bounds, ofView: button, preferredEdge: NSRectEdge.MaxY)
}
}
Note that if you're trying to add this button via Interface Builder:
Select the button
Switch to Attributes inspector
Delete the button Title
Insert: NSShareTemplate as the Image name.
It doesn't look right to me in XCode, but works fine when run.
PS - This appears to be a case where you need to use the System Icon string value (NSShareTemplate) instead of the constant (NSImageNameShareTemplate).
Related
I'm working on a cross platform app that doesn't use NIB files and trying to figure out how to create the standard OS X "Services" menu (a submenu of the application menu in most applications).
Looking at the nib file for standard Cocoa app, the services menu is defined like this:
<menuItem title="Services" id="NMo-om-nkz">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Services" systemMenu="services" id="hz9-B4-Xy5"/>
</menuItem>
Obviously the bit that makes it work is systemMenu="services" but I can't see how to programmitically create a NSMenu item like this - there's no "systemMenu" property on NSMenu.
What magic is happening here?
You find the Services menu on NSApplication.
-[NSApplication servicesMenu]
See documentation.
For future reference, based on #catlan's answer here's some code...
// Create the services menu
NSApp.servicesMenu = [[NSMenu alloc] init];
// Create menu item for it
NSMenuItem* servicesItem = [[NSMenuItem alloc] init];
servicesItem.title = #"Services";
servicesItem.submenu = NSApp.servicesMenu;
// Add it to the app menu
NSMenu* appMenu = [[NSApp mainMenu] itemAtIndex:0].submenu;
[appMenu addItem:servicesItem];
My goal is simple and yet I cannot find a solution in spite of lots of searching.
Basically, when my app is in full-screen (kiosk) mode, I want the toolbar only to auto-hide, but I want the menu bar hidden.
Apparently this combination is not valid. I've tried:
- (NSApplicationPresentationOptions)window:(NSWindow *)window willUseFullScreenPresentationOptions: (NSApplicationPresentationOptions)proposedOptions
{
return (NSApplicationPresentationFullScreen |
NSApplicationPresentationHideDock |
NSApplicationPresentationHideMenuBar |
NSApplicationPresentationAutoHideToolbar);
}
I get the following exception:
"... fullscreen presentation options must include NSApplicationPresentationAutoHideMenuBar if NSApplicationPresentationAutoHideToolbar is included"
Thing is, I don't want the menu bar displayed at all!
So, I'm presuming this is not possible using the standard presentation options. Any ideas how I might approach implementing this behaviour manually?
I'm thinking along the lines of: detect the mouse position and only show/hide the toolbar when the mouse is at/near the top of the screen.
I'm very new to Cocoa so not sure where I would start to achieve this. Any help much appreciated!
Many thanks,
John
I've got It to work, but only by using private APIs.
First I had to find out how to prevent the menubar from appearing. I discovered the functions _HIMenuBarPositionLock and _HIMenuBarPositionUnlock, from Carbon (link the app with Carbon.framework).
Then I had to create a custom subclass of NSToolbar, at awakeFromNib I register notification observers to lock and unlock the menubar when the window enters and exits fullscreen, respectively:
- (void)awakeFromNib
{
[super awakeFromNib];
[[NSNotificationCenter defaultCenter] addObserverForName:NSWindowWillEnterFullScreenNotification object:[self _window] queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
// lock menubar position when entering fullscreen so It doesn't appear when the mouse is at the top of the screen
_HIMenuBarPositionLock();
}];
[[NSNotificationCenter defaultCenter] addObserverForName:NSWindowWillExitFullScreenNotification object:[self _window] queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *note) {
// unlock menubar position when exiting fullscreen
_HIMenuBarPositionUnlock();
}];
[self _setupToolbarHotspotTrackingView];
}
_setupToolbarHotspotTrackingView is a method on SOToolbar which adds a view to the window, this view will be used to track the mouse location and show/hide the toolbar accordingly.
- (void)_setupToolbarHotspotTrackingView
{
NSView *contentView = [self _window].contentView;
self.toolbarHotspotTrackingView = [[SOToolbarTrackingView alloc] initWithFrame:contentView.bounds];
[contentView addSubview:self.toolbarHotspotTrackingView];
self.toolbarHotspotTrackingView.autoresizingMask = NSViewWidthSizable|NSViewHeightSizable;
self.toolbarHotspotTrackingView.toolbar = self;
}
I also had to override _attachesToMenuBar on SOToolbar so the animation works properly.
- (BOOL)_attachesToMenuBar
{
return NO;
}
SOToolbarTrackingView sets up a tracking area for mouse moved events and checks to see if the mouse is at the top of the window. It then calls some methods on the private class NSToolbarFullScreenWindowManager to show and hide the toolbar.
There's too much stuff to explain It all in detail here, I've uploaded my experimental project so you can take a look. Download the sample project here.
How to implement: I have UIBarButtonItem with a search icon, after I click on it, I want to show the search bar in navigation bar and on click cancel button in search bar, I want to show navigation bar without search and with buttons and title like in IOS 7 calendar app.
Setup an action for your search button to present a UISearchController. See the Search > Present Over Navigation Bar demo in Apple's UICatalog sample code:
- (IBAction)searchButtonClicked:(UIBarButtonItem *)sender {
// Create the search results view controller and use it for the UISearchController.
AAPLSearchResultsViewController *searchResultsController = [self.storyboard instantiateViewControllerWithIdentifier:AAPLSearchResultsViewControllerStoryboardIdentifier];
// Create the search controller and make it perform the results updating.
self.searchController = [[UISearchController alloc] initWithSearchResultsController:searchResultsController];
self.searchController.searchResultsUpdater = searchResultsController;
self.searchController.hidesNavigationBarDuringPresentation = NO;
// Present the view controller.
[self presentViewController:self.searchController animated:YES completion:nil];
}
Is there a way to tell OS X to automatically style/tint a NSToolbarItem?
I've added an "Image Toolbar Item" via IB/Xcode and set the icon to a black PDF as described in the documentation.
However, my result does not resemble that of, for instance, the App Store:
I'm looking for something akin to what the TabBar in iOS does by default.
I'm new to OS X development... So any guidance would be appriciated!
Images need to be made template'd in order to get the correct styling (such as the engraved & blue styling).
This can be done in code with -[NSImage setTemplate:] or by having your image names end with "Template" (requiring no code changes).
To get the blue styling specifically, you have to set a borderless NSButton as the custom view of the toolbar item (rather than it being a standard item). That button has to have a type that results in it showing its state (e.g. a Round-Textured Toggle button), and when it has an On state, it will get then blue styling.
If you're trying to create a tinted toolbar item in code, This is how I did it. Create the correct type of button NSButtonTypeToggle then set the buttons properties, then add the button to the toolbar item's custom view and finally the toolbar item is returned.
- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSToolbarItemIdentifier)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag {
// create toolbar items
NSToolbarItem *toolbarItem = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
toolbarItem.label = #"title";
NSImage *iconImage = [NSImage imageNamed:NSImageNameColumnViewTemplate];
NSButton *button = [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 40.0, 40.0)];
button.title = #"";
button.image = iconImage;
[button setButtonType:NSButtonTypeToggle];
button.bezelStyle = NSBezelStyleTexturedRounded;
button.action = #selector(toggleColumnView:);
[toolbarItem setView:button];
return toolbarItem;
}
I am trying to recreate the nice textured buttons like Finder, Safari and Transmission have in their toolbar. First I started by just dragging in a "Texture button" in the IB and such. All works well except for when a user sets the toolbar to "Text only" mode. When he then clicks the button the toolbar will enable "Icon and Label" on it's own. I have remove alles code and delegates from the toolbar to make sure it is not a code issue.
Then, just to make sure, I created a new project (no code at all) and I can reproduce the issue with a clean NSWindow with a NSToolbar with one NSToolbarItem with a NSButton in it.
Adding the NSButtons via code like:
- (NSArray*)toolbarAllowedItemIdentifiers:(NSToolbar*)toolbar {
return [NSArray arrayWithObject:#"myToolbarMenu"];
}
- (NSArray*)toolbarDefaultItemIdentifiers:(NSToolbar*)toolbar {
return [self toolbarAllowedItemIdentifiers:toolbar];
}
- (NSToolbarItem*)toolbar:(NSToolbar*)toolbar
itemForItemIdentifier:(NSString*)str
willBeInsertedIntoToolbar:(BOOL)flag
{
if ([str isEqualToString:#"myToolbarItem"] == YES) {
NSToolbarItem* item = [[NSToolbarItem alloc] initWithItemIdentifier:str];
[item setView:[[NSButton alloc] init]];
[item setMinSize:NSMakeSize(50,50)];
[item setMaxSize:NSMakeSize(50,50)];
[item setLabel:#"Text"];
return [item autorelease];
}
return nil;
}
But this also has the same effect: when I press a NSToolbarItem with a NSButton in it in "Text only mode" the toolbar itself forces it's mode to "Icon and Text".
Do you have any idea how I can make it work correctly or perhaps have an alternative to creating the nice looking toolbaritems like Safari etc have?
You need to add a menu representation to each NSToolbarItem that has a custom view. Below the line where you allocate the NSToolbarItem add this:
NSMenuItem *menuRep = [[NSMenuItem alloc] initWithTitle:#"Text" action:#selector(targetMethod:) keyEquivalent:#""];
[menuRep setTarget:<target>];
[item setMenuFormRepresentation:menuRep];
As long as the target is valid your items should stay as text-only buttons; otherwise they will be disabled. See Setting a Toolbar Item's Representation.
Normally you would also need to implement validateToolbarItem: in your target, but for custom view items you instead need to override validate: to do something appropriate. See Validating Toolbar Items.