A Menu with Two Columns? - swift

I'm attempting to figure out how to introduce a second column to Material's Menu, but am finding controlling two using the same View Controller's menu delegate methods tricky. Might there be a trivial way to accomplish this that I haven't thought of? I could probably make another View Controller be a second Menu's delegate, but this doesn't seem an elegant solution.
Cheers!

If you are using the Menu object itself, and not the MenuController, you should be able to do a compare in the delegation method, where you compare the menu being called with your view controller declaration property for either Menu. For example:
extension ViewController: MenuDelegate {
func menu(menu: Menu, tappedAt point: CGPoint, isOutside: Bool) {
if menu == menuA {
} else if menu == menuB {
}
}
}
Now you should only need to do this if the functionality differs for each columns menu. If you need any further help, please share you code :)

Related

How to override Copy and Paste NSMenuItems for one View Controller Swift macOS

I am writing a macOS application with multiple view controllers, using Storyboards.
In my main View Controller I would like to be able to copy and paste data to the NSPasteboard. The data is related to buttons displayed to the user, and the exact data to be copied varies depending on which button has most recently been pressed/selected.
I would like to be able to override the standard behaviour of the Copy and Paste NSMenuItems when my main View Controller is the front most (key) window, but revert to back to standard behaviour when other windows are in the foreground, as they all contain NSTextFields which can be copied/pasted into.
I have done a lot of googling, and overriding this behaviour is not very well documented. I can achieve it globally by adding an IBAction into the App Delegate, which I could use to call a function in whichever View Controller is key, but this doesn't feel like a very elegant solution.
Currently my IBAction in the App Delegate looks like this:
#IBAction func copy(_ sender: Any) {
if let window = NSApplication.shared.keyWindow {
if let splitView = window.contentViewController as? SplitViewController {
if let controlVC = splitView.controlItem.viewController as? ControlViewController {
controlVC.copyAction(self)
}
}
}
}
Am I missing a neater solution?
Thanks,
Dan

Swift - TabBarController - Decide segue at runtime

i have the following situation:
In my TabBarController i have multiple tabs and it all works fine, but:
The destination of one specific tab is dynamic.
If a certain condition matches, this specific tab should open a NavigationViewController.
If an other condition matches, this specific tab should open a ViewController.
Are there any built in solutions?
How can i modify the destination of a tab at runtime?
Greetings and thanks
Long long ago, in a galaxy far far away...
Segues didn't even exist. So yeah
The UITabBarController has a setter in which you can pass the new view controllers you want it to handle. You won't be able to decide what shows at the point of the tapping this way, but you'll be able to change the controllers as the condition changes.
open func setViewControllers(_ viewControllers: [UIViewController]?, animated: Bool)
If you however DO need to decide as the tab is tapped... You could have your tab controller direct to a controller that's essentially empty, and use view controller containment for that controller to have the 2 options on it, and have one of them hidden. Pretty doable from the storyboard with very little supporting code. I think I prefer this option.
If you would rather continue to use Segues, then you can perform a specific Segue depending on the state of some condition variable like this:
func presentAppropriateView() {
if condition {
performSegue(withIdentifier: "ToNavBar", sender: self)
} else {
performSegue(withIdentifier: "ToVC", sender: self)
}
}
write a delegate method which you want to perform on certain condition on runtime and call
[self.tabBarController setSelectedIndex:0];
where index could be of your choice

Shake Gesture not Working

I have a project set up using SWReveal for the slide out menu.
When I place a motion ended override function it never seems to be called even though everything else in the class loads (indicated with the 'loading'.
I have had a good play around and found that if I change the segue to the page to a 'show' segue the code functions as I would expect it to.
However when I use a custom segue with the SWReveal as the class the motion ended does not work.
I have attached a screen shot to help describe the issue.
Any help much appreciated.
You need to override canBecomeFirstResponder method.
override func canBecomeFirstResponder() -> Bool {
return true
}

swift - call code from another view controller

I'm using a library that manages the swiping between view controllers.
It seems like the only way that I can use a button in one of my view controller to navigate to the other is by calling a specific method from the view controller that manages the swiping feature.
It there any way to call a method in a different view controller?
Thank you
There are many ways to communicate between view controllers. One of the most common patterns for doing so on iOS is the delegate pattern. One view controller holds a reference to the other and the delegate conforms to a protocol. The protocol is a set of methods that the first view controller can call when specific events happen. I would try setting up a protocol and have one of your view controllers be a delegate to the other
If you take a look at the code that is hosted on GitHub you can see that the page controller is exposed from the EZSwipeController class. So given that you subclass EZSwipeController (or maintain a reference somewhere), you can now access the pageViewController property of it and scroll to a given page.
If you subclass:
class MyVC : EZSwipeController{
func buttonTapped(){ /* use self.pageViewController to "page" */ }
}
Weirdly, I have never personally worked with UIPageViewController, and as far as I can tell there is no easy way to scroll to a page in an easy fashion.
I haven't personally tried it (I usually validate my answers before posting), but you should be able to pull it off. If you don't have a reference to the view controller you need to get it (let me know if that is the core issue).
There is a question on SO that seems to enjoy some popularity regarding UIPageViewController paging:
UIPageViewController, how do I correctly jump to a specific page without messing up the order specified by the data source?
And from Apple docs:
I would also encourage you to look at the code inside of the EZSwipeController repo, where you can find a non-exposed method that does the scrolling:
#objc private func clickedLeftButton() {
let currentIndex = stackPageVC.indexOf(currentStackVC)!
datasource?.clickedLeftButtonFromPageIndex?(currentIndex)
let shouldDisableSwipe = datasource?.disableSwipingForLeftButtonAtPageIndex?(currentIndex) ?? false
if shouldDisableSwipe {
return
}
if currentStackVC == stackPageVC.first {
return
}
currentStackVC = stackPageVC[currentIndex - 1]
pageViewController.setViewControllers([currentStackVC], direction: UIPageViewControllerNavigationDirection.Reverse, animated: true, completion: nil)
}
The "key" line is this one:
pageViewController.setViewControllers([currentStackVC], direction: UIPageViewControllerNavigationDirection.Reverse, animated: true, completion: nil)
I think EZSwipeController also exposes the view controllers contained in the pageViewController which is a property called stackVC, which is an array of the view controllers contained in the page view controller.
I assume with this knowledge you should be able to page to a given page, despite seeming a little "hacky" (IMHO the developers should have exposed paging logic from the get-go).
My advice for you after all this is simple:
Try to roll it yourself. This is not a huge undertaking and you maintain full control over what's accessible and how you want to work with it. The EZSwipeController class is quite small, so there is not a whole lot of code you'd have to write for your own solution. You could also go ahead and fork the repo and modify/use it to your liking.
I hope that helps. If you have any further questions or if something is unclear, I'd be ready to help you out.

Swift and watchkit: pushControllerWithName not being called at all

I have always used the pushControlledWithName method in swift/watchkit to move to another interface controller, basically like this:
self.pushControllerWithName("newinterfacecontroller", context: nil)
In some of my projects, when I put this in a function (like where the user presses a button) it simply doesn't get called at all. No errors, just as if the code isn't there at all. If I create a new test project and try it it works. I am baffled as to what's going on here.
Example of what happens:
#IBAction func button1Action() {
println("test")
self.pushControllerWithName("newinterfacecontroller", context: nil)
}
Pressing the button will print "test" in the console, but it doesn't try to move to the new interface controller (with identifier "newinterfacecontroller") at all.
I think you've figured this out from the comments, but page-based interfaces are technically modals and not navigation-stack interfaces.
You can present modals from anywhere, but you can only push onto a navigation stack from a non-modal.