The Apples Human Interface Guidelines say:
macOS Human Interface Guidelines: Panels
How do I make the very first titlebar in that image (with only a close button). Disabling both Resize and Minimize in IB only make the resize/minimize buttons get disabled. But I want them to disappear. How can I do that?
I believe this should work:
[[window standardWindowButton:NSWindowCloseButton] setHidden:YES];
[[window standardWindowButton:NSWindowMiniaturizeButton] setHidden:YES];
[[window standardWindowButton:NSWindowZoomButton] setHidden:YES];
Swift code for accepted answer
window!.standardWindowButton(.miniaturizeButton)!.isHidden = true
window!.standardWindowButton(.zoomButton)!.isHidden = true
window!.standardWindowButton(.closeButton)!.isHidden = true
I also needed this but visible for mouse overs - Swift:
var trackingTag: NSTrackingRectTag?
override func mouseEntered(with theEvent: NSEvent) {
if trackingTag == theEvent.trackingNumber {
window!.standardWindowButton(.closeButton)!.alphaValue = 1.00
}
}
override func mouseExited(with theEvent: NSEvent) {
if trackingTag == theEvent.trackingNumber {
window!.standardWindowButton(.closeButton)!.alphaValue = 0.01
}
}
func updateTrackingAreas(_ establish : Bool) {
if let tag = trackingTag {
window!.standardWindowButton(.closeButton)!.removeTrackingRect(tag)
}
if establish, let closeButton = window!.standardWindowButton(.closeButton) {
trackingTag = closeButton.addTrackingRect(closeButton.bounds, owner: self, userData: nil, assumeInside: false)
}
}
override func windowDidLoad() {
window!.ignoresMouseEvents = false
updateTrackingAreas(true)
window!.standardWindowButton(.closeButton)!.alphaValue = 0.01
}
func windowShouldClose(_ sender: Any) -> Bool {
window!.ignoresMouseEvents = true
updateTrackingAreas(false)
return true
}
Visibility is needed but just slightly - 0.01 opacity, to have the tracking area effective.
another way is...
for (id subview in [self window].contentView.superview.subviews) {
if ([subview isKindOfClass:NSClassFromString(#"NSTitlebarContainerView")]) {
NSView *titlebarView = [subview subviews][0];
for (id button in titlebarView.subviews) {
if ([button isKindOfClass:[NSButton class]]) {
[button setHidden:YES];
}
}
}
}
Related
I'm new to tvOS. I have created UICollectionView using a XIB file in Objective-C. How can I focus UICollectionViewCell?
I have a label and an image view in the cell, and I want to focus both the label and the image view.
UICollectionViewCell are not focus appearance by default, but you can achive this by adding one yourself.
- (void)didUpdateFocusInContext:(UIFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator
{
if (self.focused)
{
// Apply focused appearence,
// e.g scale both of them using transform or apply background color
}
else
{
// Apply normal appearance
}
}
OR
If you just want to focus ImageView like scaling it up when collection view cell get focus you can do like this in awakeFromNib method
self.imageView.adjustsImageWhenAncestorFocused = YES;
self.clipToBounds = NO;
Add this in custom class of collectionview:
override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) {
if (self.focused) {
collectionView.image.adjustsImageWhenAncestorFocused = true
} else {
collectionView.image.adjustsImageWhenAncestorFocused = false
}
}
Add below methods to your collectionview cell.It will show title of focussed cell only giving complete look and feel of focus.
override func awakeFromNib() {
super.awakeFromNib()
// These properties are also exposed in Interface Builder.
imageView.adjustsImageWhenAncestorFocused = true
imageView.clipsToBounds = false
title.alpha = 0.0
}
// MARK: UICollectionReusableView
override func prepareForReuse() {
super.prepareForReuse()
// Reset the label's alpha value so it's initially hidden.
title.alpha = 0.0
}
// MARK: UIFocusEnvironment
override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator) {
/*
Update the label's alpha value using the `UIFocusAnimationCoordinator`.
This will ensure all animations run alongside each other when the focus
changes.
*/
coordinator.addCoordinatedAnimations({
if self.focused {
self.title.alpha = 1.0
}
else {
self.title.alpha = 0.0
}
}, completion: nil)
}
All I want to do is add a background color to a button for all states. But I want to maintain the automatic focus shadow that you get "for free" when using a system button in the tvOS storyboard. So far I haven't been able to find a combination that allows this.
Alternatively, I would also be interested in a way to programmatically add the shadow when the button is focused, but short of subclassing the button (which I haven't yet tried), I don't know how to do that either.
You can add a shadow for your custom button like this:
- (void)didUpdateFocusInContext:(UIFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator
{
context.nextFocusedView.layer.shadowOffset = CGSizeMake(0, 10);
context.nextFocusedView.layer.shadowOpacity = 0.6;
context.nextFocusedView.layer.shadowRadius = 15;
context.nextFocusedView.layer.shadowColor = [UIColor blackColor].CGColor;
context.previouslyFocusedView.layer.shadowOpacity = 0;
}
Wasn't happy with a simple colour change, so I made a custom button subclass to look more like the default animation you get with system buttons -
class CustomButton: UIButton
{
private var initialBackgroundColour: UIColor!
required init?(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
initialBackgroundColour = backgroundColor
}
override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator)
{
coordinator.addCoordinatedAnimations(
{
if self.focused
{
self.backgroundColor = UIColor.whiteColor()
UIView.animateWithDuration(0.2, animations:
{
self.transform = CGAffineTransformMakeScale(1.1, 1.1)
},
completion:
{
finished in
UIView.animateWithDuration(0.2, animations:
{
self.transform = CGAffineTransformIdentity
},
completion: nil)
})
}
else
{
self.backgroundColor = self.initialBackgroundColour
}
},
completion: nil)
}
}
Nothing too complicated, but gets the job done
Override didUpdateFocusInContext method and check if next focus view is button, if yes then customize its UI, and to set it back to orignal state check context.previousFocusedView was that button, something like below
- (void)didUpdateFocusInContext:(UIFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator
{
if (context.nextFocusedView == _button)
{
// set background color
}
else if (context.previousFocusedView == _button)
{
// set background color to background
}
}
The Ultimate Solution with inspiration from SomaMan. Just subclass all your custom buttons and you Get this:
includes: on tap animation and release and drag away.
//
// CustomFocusButton.swift
//
import UIKit
class CustomFocusButton: UIButton {
let focusedScaleFactor : CGFloat = 1.2
let focusedShadowRadius : CGFloat = 10
let focusedShadowOpacity : Float = 0.25
let shadowColor = UIColor.blackColor().CGColor
let shadowOffSetFocused = CGSizeMake(0, 27)
let animationDuration = 0.2
override func didUpdateFocusInContext(context: UIFocusUpdateContext, withAnimationCoordinator coordinator: UIFocusAnimationCoordinator)
{
coordinator.addCoordinatedAnimations({
if self.focused{
UIView.animateWithDuration(self.animationDuration, animations:{ [weak self] () -> Void in
guard let weakSelf = self else {return}
weakSelf.transform = CGAffineTransformMakeScale(weakSelf.focusedScaleFactor, weakSelf.focusedScaleFactor)
weakSelf.clipsToBounds = false
weakSelf.layer.shadowOpacity = weakSelf.focusedShadowOpacity
weakSelf.layer.shadowRadius = weakSelf.focusedShadowRadius
weakSelf.layer.shadowColor = weakSelf.shadowColor
weakSelf.layer.shadowOffset = weakSelf.shadowOffSetFocused
},completion:{ [weak self] finished in
guard let weakSelf = self else {return}
if !finished{
weakSelf.transform = CGAffineTransformMakeScale(weakSelf.focusedScaleFactor, weakSelf.focusedScaleFactor)
weakSelf.clipsToBounds = false
weakSelf.layer.shadowOpacity = weakSelf.focusedShadowOpacity
weakSelf.layer.shadowRadius = weakSelf.focusedShadowRadius
weakSelf.layer.shadowColor = weakSelf.shadowColor
weakSelf.layer.shadowOffset = weakSelf.shadowOffSetFocused
}
})
} else {
UIView.animateWithDuration(self.animationDuration, animations:{ [weak self] () -> Void in
guard let weakSelf = self else {return}
weakSelf.clipsToBounds = true
weakSelf.transform = CGAffineTransformIdentity
}, completion: {[weak self] finished in
guard let weakSelf = self else {return}
if !finished{
weakSelf.clipsToBounds = true
weakSelf.transform = CGAffineTransformIdentity
}
})
}
}, completion: nil)
}
override func pressesBegan(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
UIView.animateWithDuration(animationDuration, animations: { [weak self] () -> Void in
guard let weakSelf = self else {return}
weakSelf.transform = CGAffineTransformIdentity
weakSelf.layer.shadowOffset = CGSizeMake(0, 10);
})
}
override func pressesCancelled(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
if focused{
UIView.animateWithDuration(animationDuration, animations: { [weak self] () -> Void in
guard let weakSelf = self else {return}
weakSelf.transform = CGAffineTransformMakeScale(weakSelf.focusedScaleFactor, weakSelf.focusedScaleFactor)
weakSelf.layer.shadowOffset = weakSelf.shadowOffSetFocused
})
}
}
override func pressesEnded(presses: Set<UIPress>, withEvent event: UIPressesEvent?) {
if focused{
UIView.animateWithDuration(animationDuration, animations: {[weak self] () -> Void in
guard let weakSelf = self else {return}
weakSelf.transform = CGAffineTransformMakeScale(weakSelf.focusedScaleFactor, weakSelf.focusedScaleFactor)
weakSelf.layer.shadowOffset = weakSelf.shadowOffSetFocused
})
}
}
}
I've found something better:
-(void)didUpdateFocusInContext:(UIFocusUpdateContext *)context withAnimationCoordinator:(UIFocusAnimationCoordinator *)coordinator {
[coordinator addCoordinatedAnimations:^{
if (self.focused) {
self.backgroundColor = [UIColor whiteColor];
}
else {
self.backgroundColor = [UIColor clearColor];
}
} completion:nil];
}
Swift 4 /tvOS11 and better:
Set the ButtonType in the Interface Builder button properties to "Plain".
Add this private extension to your class:
private extension UIImage {
static func imageWithColor(color: UIColor, size: CGSize) -> UIImage? {
let rect = CGRect(x: 0, y: 0, width: size.width, height: size.height)
UIGraphicsBeginImageContextWithOptions(size, false, 0)
color.setFill()
UIRectFill(rect)
let image: UIImage? = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}
Then in your connected IBOutlet set the background image for the focused state of the button:
#IBOutlet weak var myButton: UIButton! {
didSet {
let backgroundImageSelected = UIImage.imageWithColor(color: .red, size: myButton.bounds.size)
myButton.setBackgroundImage(backgroundImageSelected, for: .focused)
}
}
You can use the UIButton method setBackgroundImage(image: UIImage?, forState state: UIControlState) and pass through an image that is a flat color and the state .Normal.
This image can easily be created programatically from a UIColor and a size of 1x1:
func getImageWithColor(color: UIColor, size: CGSize) -> UIImage {
let rect = CGRectMake(0, 0, size.width, size.height)
UIGraphicsBeginImageContextWithOptions(size, false, 0)
color.setFill()
UIRectFill(rect)
let image: UIImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
You can set the background image in storyboard to an image that contains the color you would like
I want to make my tableView act like this:
When the mouse swipe over a certain row, the row will be highlighted, just like the mouseOver event of a button
It took me some time to work on it based on this hint.
It works for me, correct me if I'm wrong.
Tested with Swift 3.0.2 on macOS 10.12.2 and Xcode 8.2.1
//
// Created by longkai on 30/12/2016.
// Copyright (c) 2016 xiaolongtongxue.com. All rights reserved.
//
import Cocoa
class InboxTableCellView: NSTableCellView {
// MARK: - Outlets
#IBOutlet weak var title: NSTextField!
#IBOutlet weak var sender: NSTextField!
#IBOutlet weak var time: NSTextField!
#IBOutlet weak var snippet: NSTextField!
// MARK: - Mouse hover
deinit {
removeTrackingArea(trackingArea)
}
private var trackingArea: NSTrackingArea!
override func awakeFromNib() {
super.awakeFromNib()
self.trackingArea = NSTrackingArea(
rect: bounds,
options: [NSTrackingAreaOptions.activeAlways, NSTrackingAreaOptions.mouseEnteredAndExited,/* NSTrackingAreaOptions.mouseMoved */],
owner: self,
userInfo: nil
)
addTrackingArea(trackingArea)
}
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
NSColor(red: 0.96, green: 0.96, blue: 0.96, alpha: 1.00).set()
// mouse hover
if highlight {
let path = NSBezierPath(rect: bounds)
path.fill()
}
// draw divider
let rect = NSRect(x: 0, y: bounds.height - 2, width: bounds.width, height: bounds.height)
let path = NSBezierPath(rect: rect)
path.fill()
}
private var highlight = false {
didSet {
setNeedsDisplay(bounds)
}
}
override func mouseEntered(with event: NSEvent) {
super.mouseEntered(with: event)
if !highlight {
highlight = true
}
}
override func mouseExited(with event: NSEvent) {
super.mouseExited(with: event)
if highlight {
highlight = false
}
}
}
You need to create a subclass and use tracking areas. That's what buttons do to track mouse hovering.
There's an Apple Sample Code that does exactly what you need - highlighting rows on hover:
HoverTableDemo
It's been thoroughly discussed in WWDC 2011 Session 120
(Ignoring the "Mouse Over is bad GUI" sermon (which you'll ignore anyway… ;-))
#import "MoTableView.h"
#implementation MoTableView
{
NSUInteger mouseRow;
NSRect mouseRowFrame;
}
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
mouseRow = -1;
}
return self;
}
- (void)awakeFromNib
{
[self.window setAcceptsMouseMovedEvents:YES];
}
- (void)drawRect:(NSRect)dirtyRect
{
[super drawRect:dirtyRect];
// Drawing code here.
[[NSColor redColor] set];
NSLogDebug(#"mouseRowFrame: %#", NSStringFromRect(mouseRowFrame));
NSFrameRectWithWidth(mouseRowFrame, 2.);
}
- (void)mouseMoved:(NSEvent *)theEvent
{
NSPoint mouseLocation = [theEvent locationInWindow];
NSPoint viewLocation = [self convertPoint:mouseLocation fromView:nil] ;
NSInteger row = [self rowAtPoint:viewLocation];
if (row != mouseRow) {
mouseRowFrame = [self rectOfRow:row];
[self setNeedsDisplay];
mouseRow = row;
}
}
#end
I'm using a storyboard container view. So I have a view controller containing a container view. I have a second, smaller view in the storyboard, which is embedded in that container via an embed segue. So far so good.
Now I would like to be able to switch the contents of that container view dynamically, when the user taps a button. The button will be on the main, larger, view. I have made another view controller of the same smaller size, and given it a different storyboard ID.
However, I can't work out how to code the switch. I can only create a single embed segue for that container.
Any help gratefully received.
You need to use the custom container view controller api to do the switching of the controllers. The following code shows one way to do that. In this project I had a segmented control in the main view controller (the one with the container view) that switches beetween the two controllers. initialVC is the controller that's embedded in IB, and substituteVC is the one I'm switching to. The property, container, is an IBOutlet to the container view.
- (void)viewDidLoad {
[super viewDidLoad];
self.initialVC = self.childViewControllers.lastObject;
self.substituteVC = [self.storyboard instantiateViewControllerWithIdentifier:#"Substitute"];
self.currentVC = self.initialVC;
}
-(IBAction)switchControllers:(UISegmentedControl *)sender {
switch (sender.selectedSegmentIndex) {
case 0:
if (self.currentVC == self.substituteVC) {
[self addChildViewController:self.initialVC];
self.initialVC.view.frame = self.container.bounds;
[self moveToNewController:self.initialVC];
}
break;
case 1:
if (self.currentVC == self.initialVC) {
[self addChildViewController:self.substituteVC];
self.substituteVC.view.frame = self.container.bounds;
[self moveToNewController:self.substituteVC];
}
break;
default:
break;
}
}
-(void)moveToNewController:(UIViewController *) newController {
[self.currentVC willMoveToParentViewController:nil];
[self transitionFromViewController:self.currentVC toViewController:newController duration:.6 options:UIViewAnimationOptionTransitionFlipFromLeft animations:nil
completion:^(BOOL finished) {
[self.currentVC removeFromParentViewController];
[newController didMoveToParentViewController:self];
self.currentVC = newController;
}];
}
After Edit:
If you want to go to the new controller with no animation, you can do it like this (this substitutes for the code that I had under case 1).
[self addChildViewController:self.substituteVC];
[self.substituteVC didMoveToParentViewController:self];
self.substituteVC.view.frame = self.container.bounds;
[self.container addSubview:self.substituteVC.view];
[self.currentVC removeFromParentViewController];
rdelmar's answer converted to Swift syntax
override func viewDidLoad() {
super.viewDidLoad()
self.initialVC = self.childViewControllers.last
self.substituteVC = self.storyboard!.instantiateViewControllerWithIdentifier("Substitute")
self.currentVC = self.initialVC;
}
#IBAction func switchControllers(sender: UISegmentedControl) {
switch sender.selectedSegmentIndex{
case 0:
if (self.currentVC == self.substituteVC) {
self.addChildViewController(self.initialVC)
//self.initialVC.view.frame = self.containerView.bounds
moveToNewController(self.initialVC)
}
case 1:
if (self.currentVC == self.initialVC) {
self.addChildViewController(self.substituteVC)
//self.substituteVC.view.frame = self.containerView.bounds
moveToNewController(self.substituteVC)
}
default:
break;
}
}
func moveToNewController(newController : UIViewController){
self.currentVC.willMoveToParentViewController(nil)
self.transitionFromViewController(
self.currentVC!,
toViewController: newController,
duration: 0.2,
options: UIViewAnimationOptions.TransitionCrossDissolve,
animations: nil,
completion: { finished in
self.currentVC.removeFromParentViewController()
newController.didMoveToParentViewController(self)
self.currentVC = newController
})
}
If you deal with more than 2 child view controllers it's a good idea to store them in array. Also, you'll need to apply constraints every time you add a new subview to the container view. Here's a modified version of the accepted answer (using Swift 2 syntax):
import UIKit
class FooBarViewController: UIViewController
{
// MARK: - IBOutlets
#IBOutlet weak var containerView: UIView!
// MARK: - Properties
var vcs = [UIViewController]()
var currentVC: UIViewController!
// MARK: - ViewController Lifecycle
override func viewDidLoad()
{
super.viewDidLoad()
vcs.append(childViewControllers.last!)
vcs.append(storyboard!.instantiateViewControllerWithIdentifier("FooViewControler"))
vcs.append(storyboard!.instantiateViewControllerWithIdentifier("BarViewController"))
currentVC = vcs[0]
for vc in vcs {
vc.view.frame = containerView.bounds
}
}
// MARK: - Methods
func switchToViewController(targetVC: UIViewController)
{
addChildViewController(targetVC)
currentVC.willMoveToParentViewController(nil)
transitionFromViewController(
currentVC,
toViewController: targetVC,
duration: 0.0, // 0.3
options: .TransitionNone, // .TransitionCrossDissolve,
animations: nil,
completion: { finished in
self.currentVC.removeFromParentViewController()
targetVC.didMoveToParentViewController(self)
self.currentVC = targetVC
self.applyConstraints()
})
}
func applyConstraints()
{
let viewsDict = ["newSubview": currentVC.view]
currentVC.view.translatesAutoresizingMaskIntoConstraints = false
containerView.addConstraints(
NSLayoutConstraint.constraintsWithVisualFormat("H:|[newSubview]|",
options: NSLayoutFormatOptions(rawValue: 0),
metrics: nil,
views: viewsDict))
containerView.addConstraints(
NSLayoutConstraint.constraintsWithVisualFormat("V:|[newSubview]|",
options: NSLayoutFormatOptions(rawValue: 0),
metrics: nil, views:
viewsDict))
}
// MARK: - IBActions
#IBAction func switchControllers(sender: UISegmentedControl)
{
let i = sender.selectedSegmentIndex
if currentVC != vcs[i] {
self.addChildViewController(vcs[i])
switchToViewController(vcs[i])
}
}
}
I'm looking for the best way to change the backgroundColor of an NSView. I'd also like to be able to set the appropriate alpha mask for the NSView. Something like:
myView.backgroundColor = [NSColor colorWithCalibratedRed:0.227f
green:0.251f
blue:0.337
alpha:0.8];
I notice that NSWindow has this method, and I'm not a big fan of the NSColorWheel, or NSImage background options, but if they are the best, willing to use.
Yeah, your own answer was right. You could also use Cocoa methods:
- (void)drawRect:(NSRect)dirtyRect {
// set any NSColor for filling, say white:
[[NSColor whiteColor] setFill];
NSRectFill(dirtyRect);
[super drawRect:dirtyRect];
}
In Swift:
class MyView: NSView {
override func draw(_ dirtyRect: NSRect) {
super.draw(dirtyRect)
// #1d161d
NSColor(red: 0x1d/255, green: 0x16/255, blue: 0x1d/255, alpha: 1).setFill()
dirtyRect.fill()
}
}
An easy, efficient solution is to configure the view to use a Core Animation layer as its backing store. Then you can use -[CALayer setBackgroundColor:] to set the background color of the layer.
- (void)awakeFromNib {
self.wantsLayer = YES; // NSView will create a CALayer automatically
}
- (BOOL)wantsUpdateLayer {
return YES; // Tells NSView to call `updateLayer` instead of `drawRect:`
}
- (void)updateLayer {
self.layer.backgroundColor = [NSColor colorWithCalibratedRed:0.227f
green:0.251f
blue:0.337
alpha:0.8].CGColor;
}
That’s it!
If you are a storyboard lover, here is a way that you don't need any line of code.
Add NSBox as a subview to NSView and adjust NSBox's frame as the same with NSView.
In Storyboard or XIB change Title position to None, Box type to Custom, Border Type to "None", and Border color to whatever you like.
Here is a screenshot:
This is the result:
If you setWantsLayer to YES first, you can directly manipulate the layer background.
[self.view setWantsLayer:YES];
[self.view.layer setBackgroundColor:[[NSColor whiteColor] CGColor]];
Think I figured out how to do it:
- (void)drawRect:(NSRect)dirtyRect {
// Fill in background Color
CGContextRef context = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort];
CGContextSetRGBFillColor(context, 0.227,0.251,0.337,0.8);
CGContextFillRect(context, NSRectToCGRect(dirtyRect));
}
edit/update: Xcode 8.3.1 • Swift 3.1
extension NSView {
var backgroundColor: NSColor? {
get {
guard let color = layer?.backgroundColor else { return nil }
return NSColor(cgColor: color)
}
set {
wantsLayer = true
layer?.backgroundColor = newValue?.cgColor
}
}
}
usage:
let myView = NSView(frame: NSRect(x: 0, y: 0, width: 100, height: 100))
print(myView.backgroundColor ?? "none") // NSView's background hasn't been set yet = nil
myView.backgroundColor = .red // set NSView's background color to red color
print(myView.backgroundColor ?? "none")
view.addSubview(myView)
I went through all of these answers and none of them worked for me unfortunately. However, I found this extremely simple way, after about an hour of searching : )
myView.layer.backgroundColor = CGColorCreateGenericRGB(0, 0, 0, 0.9);
Best Solution :
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
self.wantsLayer = YES;
}
return self;
}
- (void)awakeFromNib
{
float r = (rand() % 255) / 255.0f;
float g = (rand() % 255) / 255.0f;
float b = (rand() % 255) / 255.0f;
if(self.layer)
{
CGColorRef color = CGColorCreateGenericRGB(r, g, b, 1.0f);
self.layer.backgroundColor = color;
CGColorRelease(color);
}
}
In Swift:
override func drawRect(dirtyRect: NSRect) {
NSColor.greenColor().setFill()
NSRectFill(dirtyRect)
super.drawRect(dirtyRect)
}
Use NSBox, which is a subclass of NSView, allowing us to easily style
Swift 3
let box = NSBox()
box.boxType = .custom
box.fillColor = NSColor.red
box.cornerRadius = 5
Without doubt the easiest way, also compatible with Color Set Assets:
Swift:
view.setValue(NSColor.white, forKey: "backgroundColor")
Objective-C:
[view setValue: NSColor.whiteColor forKey: "backgroundColor"];
Interface Builder:
Add a user defined attribute backgroundColor in the interface builder, of type NSColor.
Just set backgroundColor on the layer (after making the view layer backed).
view.wantsLayer = true
view.layer?.backgroundColor = CGColor.white
I tested the following and it worked for me (in Swift):
view.wantsLayer = true
view.layer?.backgroundColor = NSColor.blackColor().colorWithAlphaComponent(0.5).CGColor
In Swift 3, you can create an extension to do it:
extension NSView {
func setBackgroundColor(_ color: NSColor) {
wantsLayer = true
layer?.backgroundColor = color.cgColor
}
}
// how to use
btn.setBackgroundColor(NSColor.gray)
In swift you can subclass NSView and do this
class MyView:NSView {
required init?(coder: NSCoder) {
super.init(coder: coder);
self.wantsLayer = true;
self.layer?.backgroundColor = NSColor.redColor().CGColor;
}
}
This supports changing systemwide appearance (turning dark mode on or off) while the application is running. You can also set the background colour in Interface Builder, if you set the class of the view to BackgroundColorView first.
class BackgroundColorView: NSView {
#IBInspectable var backgroundColor: NSColor? {
didSet { needsDisplay = true }
}
override init(frame frameRect: NSRect) {
super.init(frame: frameRect)
wantsLayer = true
}
required init?(coder decoder: NSCoder) {
super.init(coder: decoder)
wantsLayer = true
}
override var wantsUpdateLayer: Bool { return true }
override func updateLayer() {
layer?.backgroundColor = backgroundColor?.cgColor
}
}
Have a look at RMSkinnedView. You can set the NSView's background color from within Interface Builder.
Just small reusable class (Swift 4.1)
class View: NSView {
var backgroundColor: NSColor?
convenience init() {
self.init(frame: NSRect())
}
override func draw(_ dirtyRect: NSRect) {
if let backgroundColor = backgroundColor {
backgroundColor.setFill()
dirtyRect.fill()
} else {
super.draw(dirtyRect)
}
}
}
// Usage
let view = View()
view.backgroundColor = .white