How do you reference the view's window in Swift 3.x using Storyboards/Cocoa - swift

with all the changes in Xcode and Swift, I can't figure out how to address the view's window in a stotyboard-driven project in the way I'm doing it in projects using XIBs. New to macOS programming so apologies in advance if this is basic stuff:
When using a storyboard, how do I change the view's window state using for instance:
window.titleVisibility = .hidden
window.setContentSize(size)
In an xib-driven project, I'm using
#IBOutlet weak var window: NSWindow!
but this doesn't seem to work the same way with storyboards. How do I do the same tihing using storyboards? Any help appreciated!

You can get a reference of your view window accessing its window property. Note that it can not be done inside view did load but you can create a window property for your view controller using a lazy initializer:
lazy var window: NSWindow! = self.view.window
And you can do your window customization inside the method viewWillAppear:
import Cocoa
class ViewController: NSViewController {
lazy var window: NSWindow! = self.view.window
override func viewWillAppear() {
super.viewWillAppear()
window.titleVisibility = .hidden
}
}

This seems to work:
if let window = NSApplication.shared().mainWindow {
window.titleVisibility = .hidden
}
Is this an ok way to do it?

Related

Xcode Swift MacOs - Hide/Show windows without a StoryBoard and without ViewController

I'm making an App on my Apple macOS computer by using Swift 3
Close a window is eazy [in this way] from my main window called w by clicking button and calling the function closeotherw()
#IBOutlet var w: NSWindow!
#IBOutlet var otherw: NSWindow!
#IBOutlet var otherw: NSPanel!
#IBAction func closeotherw(_ sender: AnyObject) {
otherw.close()
}
But how to reopen-it [otherwin]?
I also tried it in all ways, also like w.isHidden = true but with no results.
I don't have a StoryBoard and I also don't have a ViewController.
I'm doing all from AppDelegate.
Method is:
otherw.orderFront(self)
Also there is:
makeKeyAndOrderFront to show it again.
You can use otherw.orderOut(self) instead otherw.close()
tnks to #Willeke
reference:
How to hide the window
Good learning!

Close/Dismiss NSViewController, macOS

I have a NSViewController connected as such:
In the bottom viewController, I try to dismiss it using self.dismiss(self) however, it produces this error:
[General] dismissViewController:: Error: maybe this view controller was not presented?
How can I ever dismiss this viewcontroller?
Any help is appreciated, thanks.
So here is what I did:
In the presented window (NSViewController) add the following:
Add this to the top of the presented class as a property:
class FooViewController: NSViewController {
// reference to a window
var window: NSWindow?
...
}
Add this override of viewDidAppear, not viewDidLoad as the window handle is nil.
override func viewDidAppear() {
// After a window is displayed, get the handle to the new window.
window = self.view.window!
}
Now where you currently have "dismissViewController" you can use:
window?.performClose(nil) // nil because I'm not return a message

How to set color of NSView in Cocoa App using Swift?

I used to develop for iOS and I do not understand why I can't easily change background color of NSViews inside my main view.
Let's say I have a view controller with a main view in it. In this view I've added 3 custom views, I've set their constraints to fit the main view.
I've created 3 outlets to my view controller:
#IBOutlet weak var topView: NSView!
#IBOutlet weak var leftView: NSView!
#IBOutlet weak var rightView: NSView!
After that, I'm trying to set the background of these views and can't do this. I don't see any color changes when I run the app.
Here is the code I've added to show colors for my custom views:
override func viewDidLoad() {
super.viewDidLoad()
self.view.wantsLayer = true
self.topView.layer?.backgroundColor = NSColor.blue.cgColor
self.rightView.layer?.backgroundColor = NSColor.green.cgColor
self.leftView.layer?.backgroundColor = NSColor.yellow.cgColor
}
And it shows nothing (no background color on my views):
I can't understand why this code doesn't work. Why it is so hard to set the color of an NSView (while it is so easy in iOS development)? I'm using Xcode 8 and writing code using Swift 3.
You should set wantsLayer to true for your subviews, not for your superview.
self.topView.wantsLayer = true
self.rightView.wantsLayer = true
self.leftView.wantsLayer = true
The layer approach is convenient, but it will create a terrible issue unless you have a very dark background again a bright text color (or vice versa... I don't remember which is which any more.) for an NSTextField label. Unlike Cocoa Touch, which lets you change the background color of a UIView object, unfortunately, you have to subclass NSView in Cocoa for certainty like the following.
import Cocoa
class RedView: NSView {
override func draw(_ rect: NSRect) {
super.draw(rect)
let color = NSColor.red
color.set()
NSRectFill(rect)
}
}
Then set the class name according to whatever you call your subclass (RedView here) under the identity inspector of the interface builder. If you want to change the background color programatically, wire up the view object. Then do something like the following.
import Cocoa
class MyView: NSView {
// MARK: - Variables
var backgroundColor = NSColor()
// MARK: - Draw
override func draw(_ rect:NSRect) {
super.draw(rect)
backgroundColor.set()
NSRectFill(rect)
}
// MARK: - Method
func changeBackgroundColor(color: NSColor) {
backgroundColor = color
setNeedsDisplay(self.bounds)
}
}
You can then call changeBackgroundColor from the view controller like...
#IBOutlet weak var myView: MyView!
myView.changeBackgroundColor(color: NSColor.green)

Swift Access Objects In View Controller From Window Controller

I'm just getting into development on mac os and I made a simple app for the touch bar that allows you to change the color (with a nscolorpicker) of a label that is also on the touch bar.
Now I would like to get the same effect on the actual window like so: I change the color using the picker on the touch bar and the color of the colorwell in the window changes as well.
This is the code that I currently have for the touch bar actions:
import Cocoa
#available(OSX 10.12.2, *)
class MainWindowController: NSWindowController {
#IBOutlet weak var cptHello: NSColorPickerTouchBarItem!
#IBOutlet var lblHello: NSTextField!
override func windowDidLoad() {
super.windowDidLoad()
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
cptHello.color = NSColor.white
setCol()
}
func setCol(){
lblHello.textColor = cptHello.color
}
#IBAction func colorPicked(_ sender: Any) {
setCol()
}
}
This piece of code resides in MainWindowController.swift which is paired with the window controller.
In the view controller, I have a single NSColorWell that I would like to change the color for inside the function "setCol()". I created an outlet in the view controller for it like so:
#IBOutlet var cwHello: NSColorWell!
So ideally what I want to achieve is something like this:
func setCol(){
lblHello.textColor = cptHello.color
ViewController.cwHello.color = cptHello.color
}
Can this be done at all?

How can I use NSVisualEffectView to blend window with background

There seem to be a bunch of questions on this for old versions of Swift/Xcode, but for some reason it hasn't been working with the latest update. I created a NSVisualEffectView, blurryView, and added the subview to my main view:
class ViewController: NSViewController {
#IBOutlet weak var blurryView: NSVisualEffectView!
override func viewDidLoad() {
super.viewDidLoad()
//background styling
blurryView.wantsLayer = true
blurryView.blendingMode = NSVisualEffectBlendingMode.behindWindow
blurryView.material = NSVisualEffectMaterial.dark
blurryView.state = NSVisualEffectState.active
self.view.addSubview(blurryView, positioned: NSWindowOrderingMode.above, relativeTo: nil)
// Do any additional setup after loading the view.
}
...
}
But when I run it, there is no effect on the window. (when I set it to within window, and layer it on top of my other view, the blur works correctly, but I only want the window to blur.) I also tried doing the same thing in my App Delegate class, but I can't connect my window as an outlet, and therefore can't add the blurry view to the window. Here's what the code would look like:
class AppDelegate: NSObject, NSApplicationDelegate {
func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application
blurryView.wantsLayer = true
blurryView.blendingMode = NSVisualEffectBlendingMode.withinWindow
blurryView.material = NSVisualEffectMaterial.dark
blurryView.state = NSVisualEffectState.active
self.window.contentView?.addSubview(blurryView)
}
...
}
To get an idea if what I'm looking for: NSVisualEffectView Vibrancy
It works quite easy:
In Interface Builder drag a NSVisualEffectView directly as a subview of the main view of your scene.
In the Properties Inspector set Blending Mode to Behind Window
Add the rest of the views you need as subviews of the NSVisualEffectView
That's it, you're done
Here's an example:
Panel 1 View Controller is my blurred view, Background View is the first (non-blurred) view in my "real"view hierarchy.
Swift 5:
Simply add this to your viewWillAppear and it should work:
override func viewWillAppear() {
super.viewWillAppear()
//Adds transparency to the app
view.window?.isOpaque = false
view.window?.alphaValue = 0.98 //you can remove this line but it adds a nice effect to it
let blurView = NSVisualEffectView(frame: view.bounds)
blurView.blendingMode = .behindWindow
blurView.material = .fullScreenUI
blurView.state = .active
view.window?.contentView?.addSubview(blurView)
}