In xcode, using Swift, I need to be able to execute a line of code using the return key on the software keyboard.
How do I specify this?
I know how to resignFirstResponder for the software keyboard but that is all at the moment.
for a UITextField:
a UITextFieldDelegate has the method textFieldShouldReturn: that is called . Do your stuff and return NO to prevent a newline / yes for multiline
- (BOOL)textFieldShouldReturn:(UITextField*)field {
//DO your stuff
return NO; // yes to allow enter
}
for a UITextView:
the delegate has - (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text
check if text is return and do the above.
- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range replacementText:(NSString *)text {
if ( [text isEqualToString:#"\n"] ) {
//Do whatever you want
}
return YES;
}
The method itemWithTitle locates a menu item within a NSMenu. However it looks only inside the first level. I cannot find a ready-to-use method that will do the same job recursively by searching inside all the nested submenus. Or, somehow equivalently, a function that swipes NSmenu's recursively.
It looks quite incredible to me that such a thing would not exist. Maybe there is some function not directly related to NSMenu that can come in handy?
Ok, since I really need to do this clumsy workaround for a number of specific reasons (beyond the scope of this post, and quite uninteresting anyway) I ended up coding it myself.
Here is the snippet:
NSMenuItem * mitem;
while (mitem) { // loop over all menu items contained in any submenu, subsubmenu, etc.
// do something with mitem ....
mitem = next_menu_item(mitem);
}
which is powered by the functions:
NSMenuItem * goto_submenu(NSMenuItem * mitem){
NSMenu * submen = [mitem submenu];
if (submen && [[submen title] isNotEqualTo:#""] && [submen numberOfItems])
return goto_submenu([submen itemAtIndex:0]);
return mitem;
};
NSMenuItem * next_menu_item(NSMenuItem * mitem){
NSMenu * menu = [mitem menu];
if ([menu indexOfItem:mitem]==([menu numberOfItems]-1)) //if is last item in submenu go to parent item
return [mitem parentItem];
return goto_submenu([menu itemAtIndex:([menu indexOfItem:mitem]+1)]);
};
#implementation NSMenu (UT)
- (NSMenuItem *)itemWithTitle:(NSString *)title recursive:(BOOL)recursive {
if (recursive) {
for (NSMenuItem *item in self.itemArray) {
if ([item.title isEqualToString:title]) {
return item;
} else if (item.submenu) {
NSMenuItem *result = [item.submenu itemWithTitle:title recursive:recursive];
if (result) {
return result;
}
}
}
return nil;
} else {
return [self itemWithTitle:title];
}
}
- (NSMenuItem *)itemWithTag:(NSInteger)tag recursive:(BOOL)recursive {
if (recursive) {
for (NSMenuItem *item in self.itemArray) {
if (item.tag == tag) {
return item;
} else if (item.submenu) {
NSMenuItem *result = [item.submenu itemWithTag:tag recursive:recursive];
if (result) {
return result;
}
}
}
return nil;
} else {
return [self itemWithTag:tag];
}
}
#end
I am just start to learning about Xcode. i need to create an app in which it should be able to view correct manner in all the view (Landscape, Portrait). Condition here is should not using the auto layout.
Is any other way to use the story board for the same solution?
Other way is you have to programmatically handle the frame and other things in the following delegate functions. I have shown code for landscape mode only
//THis only work for ios<6.0
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if(interfaceOrientation== UIInterfaceOrientationPortrait || interfaceOrientation==UIInterfaceOrientationPortraitUpsideDown )
{
return NO;
}
else
{
return YES;
}
}
//THis work for ios >=6.0
- (BOOL)shouldAutorotate
{
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
UIInterfaceOrientation interfaceOrientation=[[UIApplication sharedApplication] statusBarOrientation];
if(interfaceOrientation== UIInterfaceOrientationPortrait || interfaceOrientation==UIInterfaceOrientationPortraitUpsideDown )
{
return NO;
}
else
{
//landscape mode code
return ( UIInterfaceOrientationMaskLandscapeLeft | UIInterfaceOrientationMaskLandscapeRight);
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
UIInterfaceOrientation orientation=self.interfaceOrientation;
if(orientation== UIInterfaceOrientationPortrait || orientation==UIInterfaceOrientationPortraitUpsideDown )
{
//portrait mode code
}
else
{
//landscape mode code
}
}
Sample code is
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:self selector:#selector(activeSpaceDidChange:) name:NSWorkspaceActiveSpaceDidChangeNotification object:nil];
Then
- (void) activeSpaceDidChange:(NSNotification *)aNotification {
// code to check if current workspace is dashboard?
}
I want to check whether the current space is dashboard or not? Any idea?
The first think i have tried is get to the current space id according to this answer: Detecting when a space changes in Spaces in Mac OS X . The problem here is that the key kCGWindowWorkspace is deprecated in OSX 10.8. So there is no direct way to get this information.
In my solution now i check for different windows or owners which are only one the dashboard space or on all other spaces:
The user is on the dashboard if there is one window which kCGWindowName ends with .wdgt/
The user is not on the dashboard if there is one window with kCGWindowName == System Status Item Clone, kCGWindowOwnerName == SystemUIServer | Finder
So why i'm not just using the .wdgt/ check? -- Because if there is now widget on the dashboard this not working
So why i'm using more than one window check? -. Because i'm not jet sure which window is always on all spaces. At least System Status Item Clone and Finder are not always there.
Here my implementation is add this function as category to NSWorkspace
- (BOOL) userIsOnDashboardSpace {
NSArray* windowsInSpace = (__bridge NSArray *) CGWindowListCopyWindowInfo(kCGWindowListOptionAll | kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
NSUInteger indexOfWidget = [windowsInSpace indexOfObjectPassingTest:^BOOL(NSDictionary* obj, NSUInteger idx, BOOL *stop) {
if ([obj objectForKey:(id)kCGWindowName]) {
NSString *name = (NSString *)[obj objectForKey:(id)kCGWindowName];
if ([name isEqualToString:#"System Status Item Clone"]) {
*stop = true;
return false;
}
if ([name hasSuffix:#".wdgt/"]) {
*stop = true;
return true;
}
}
if ([obj objectForKey:(id)kCGWindowOwnerName]) {
NSString *name = (NSString *)[obj objectForKey:(id)kCGWindowOwnerName];
if ([name isEqualToString:#"SystemUIServer"]) {
*stop = true;
return false;
}
if ([name isEqualToString:#"Finder"]) {
*stop = true;
return false;
}
}
return false;
}];
return indexOfWidget != NSNotFound;
}
I want to replace RBSplitView with NSSplitView in my existing project. The application is now leopard only and I would like to replace RBSplitView with the new NSSplitView shipped with Leopard.
However, I'm missing RBSplitView's handy methods expand and collapse in NSSplitView. How can I expand and collapse parts of NSSplitView programmatically?
Simply hide the subview you want to collapse, e.g.
[aSubViewToCollapse setHidden:YES];
You might also want to implement the delegate method -(BOOL)splitView:shouldHideDividerAtIndex: to return YES to hide the divider when a collapsed.
I just got programmatic expanding and collapsing of NSSplitView to work. I've also configured my NSSplitView to expand/collapse a subview whenever the divider is double-clicked, so I wanted this to play nice with that feature (and it seems to). This is what I did:
(in this example, splitView is the NSSplitView itself, splitViewSubViewLeft is the subview I wish to expand/collapse and lastSplitViewSubViewLeftWidth is an instance variable of type CGFloat.)
// subscribe to splitView's notification of subviews resizing
// (I do this in -(void)awakeFromNib)
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(mainSplitViewWillResizeSubviewsHandler:)
name:NSSplitViewWillResizeSubviewsNotification
object:splitView
];
// this is the handler the above snippet refers to
- (void) mainSplitViewWillResizeSubviewsHandler:(id)object
{
lastSplitViewSubViewLeftWidth = [splitViewSubViewLeft frame].size.width;
}
// wire this to the UI control you wish to use to toggle the
// expanded/collapsed state of splitViewSubViewLeft
- (IBAction) toggleLeftSubView:(id)sender
{
[splitView adjustSubviews];
if ([splitView isSubviewCollapsed:splitViewSubViewLeft])
[splitView
setPosition:lastSplitViewSubViewLeftWidth
ofDividerAtIndex:0
];
else
[splitView
setPosition:[splitView minPossiblePositionOfDividerAtIndex:0]
ofDividerAtIndex:0
];
}
I tried the solution above, and found it did not work, as isSubviewCollapsed never returned YES
A combination of the suggestions yielded a result which works
if ([splitViewTop isHidden]) {
[splitViewTop setHidden:NO];
[split
setPosition:previousSplitViewHeight
ofDividerAtIndex:0];
}
else {
[splitViewTop setHidden:YES];
}
[split adjustSubviews];
In El Capitan, this did the trick for me.
splitViewItem.collapsed = YES;
After some experimenting with the suggestions this was the easiest solution I found:
-(void)toggleCollapsibleView:(ib)sender {
[collapsibleView setHidden:![splitView isSubviewCollapsed:collapsibleView]];
[splitView adjustSubviews];
}
The function is a user defined first-responder action. It is triggered by a menu-item (or keystroke).
The collapsibleView is a subview in the splitView both of which are connected in IB with their properties.
In macOS Sierra, the collapsed property is changed to isCollapsed. Is straight forward just setting the property to true or false. The following code is from my WindowController, where I have two SplitViewItems.
#IBAction func toggleMap(_ sender: Any) {
if let splitViewController = contentViewController as? NSSplitViewController {
let splitViewItem = splitViewController.splitViewItems
if splitViewItem.first!.isCollapsed {
splitViewItem.first!.isCollapsed = false
} else if splitViewItem.last!.isCollapsed {
splitViewItem.last!.isCollapsed = false
} else {
if splitViewItem.first!.isCollapsed {
splitViewItem.first!.isCollapsed = false
}
splitViewItem.last!.isCollapsed = true
}
}
}
NSSplitView actually has a private method -(void)_setSubview:(NSView *)view isCollapsed:(BOOL)collapsed that does this. Those who would like to ignore all warnings against using private methods, behold:
- (void)toggleSubview:(NSView *)view {
SEL selector = #selector(_setSubview:isCollapsed:);
NSMethodSignature *signature = [NSSplitView instanceMethodSignatureForSelector:selector];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
invocation.target = self;
invocation.selector = selector;
[invocation setArgument:&view atIndex:2];
BOOL arg = ![self isSubviewCollapsed:view];
[invocation setArgument:&arg atIndex:3];
[invocation invoke];
}
I implemented this as a category on NSSplitView. The only issue is that Xcode gives a warning about _setSubview:isCollapsed: being undeclared... I'm not really sure how to get around that.
El Capitan Update
I haven't written any code for OS X in ~2 years now so I haven't been able to verify this, but according to lemonmojo in the comments below, _setSubview:isCollapsed: was renamed in El Capitan to _setArrangedView:isCollapsed:.
In swift this works
func togglePanel() {
let splitViewItem = self.mySplitView.arrangedSubviews
if mySplitView.isSubviewCollapsed(outline.view){
splitViewItem[0].hidden = false
} else {
splitViewItem[0].hidden = true
}
call this from IBAction,
outline is an OutlineViewController with own xib and we need the view hence outline.view, keeping it simple but hope you get the idea
#IBAction func segmentAction(sender: NSSegmentedControl) {
splitVC?.togglePanel(sender.selectedSegment)
}
and
func togglePanel(segmentID: Int) {
let splitViewItem = self.mySplitView.arrangedSubviews
switch segmentID {
case segmentID:
if mySplitView.isSubviewCollapsed(splitViewItem[segmentID]) {
splitViewItem[segmentID].hidden = false
} else {
splitViewItem[segmentID].hidden = true
}
default:
break
}
}
And implement delegate
func splitView(splitView: NSSplitView, shouldHideDividerAtIndex dividerIndex: Int) -> Bool {
return true
}
And with 10.11 you might just use toggleSidebar action method.
How to toggle visibility of NSSplitView subView + hide Pane Splitter divider?
https://github.com/Dis3buted/SplitViewController
I recommend to use NSSplitViewController instead, and NSSplitViewItem.isCollapsed to control them. This just work.
let item: NSSplitViewItem = ...
item.isCollapsed = true
To make this to work properly, you have to configure split-UI components with mainly view-controllers. Otherwise, it can be broken.
You could try Brandon Walkin's BWToolKit.
The BWSplitView class has a method
- (IBAction)toggleCollapse:(id)sender;
#IBOutlet weak var horizontalSplitView: NSSplitView!
var splitViewItem : [NSView]?
var isSplitViewHidden: Bool = false
override func viewDidLoad() {
super.viewDidLoad()
// To Hide Particular Sub-View.
splitViewItem = self.horizontalSplitView.arrangedSubviews
splitViewItem?[0].isHidden = true
isSplitViewHidden = true
}
//MARK: View / Manage All Jobs Button Tapped.
#IBAction func actionManageScheduleJobsButtonTapped(_ sender: Any) {
if isSplitViewHidden == true {
isSplitViewHidden = false
splitViewItem?[0].isHidden = false
} else {
isSplitViewHidden = true
splitViewItem?[0].isHidden = true
}
}
--------- OR ----------
//MARK: View / Manage All Jobs Button Tapped.
#IBAction func actionManageScheduleJobsButtonTapped(_ sender: Any) {
if splitViewItem?[0].isHidden == true {
splitViewItem?[0].isHidden = false
} else {
splitViewItem?[0].isHidden = true
}
}