xcode Interface Builder not updating IBDesignable class - ios

In my project, I have several custom class files based on UITextField and UIButton.
As an example, the UITextField class looks like this:
import UIKit
#IBDesignable class RoundedTextField: UITextField {
override func awakeFromNib() {
super.awakeFromNib()
layer.cornerRadius = 25
layer.borderWidth = 2
layer.borderColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
clipsToBounds = true
textColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
// Placeholder colour
attributedPlaceholder = NSAttributedString(string: placeholder!, attributes: [NSAttributedStringKey.foregroundColor: #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)])
}
// Placeholder text indent
override func textRect(forBounds bounds: CGRect) -> CGRect {
return bounds.insetBy(dx: 20, dy: 5)
}
// Editing text indent
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return bounds.insetBy(dx: 20, dy: 5)
}
}
Here is the correct version that the simulator shows me:
SimScreenshot
Here is what IB shows me:
IBScreenshot
As you can see from my IB screenshot, the only element that updates is the indentation of the placeholder text. The rest of the customisation from the class is not updating.
Any thoughts?
P.s. when I select an element, in the identity inspector, the 'Designables' field is "Up to date".
I have tried cleaning, building and restarting Xcode.
Thanks!
Scott

I solved the issue with help from Reinier's 2nd link and a course I previously took on Udemy.
I implemented my customisation in a setupView() function. I called this in prepareForInterfaceBuilder() and also awakeFromNib()
import UIKit
#IBDesignable class RoundedTextField: UITextField {
override func awakeFromNib() {
super.awakeFromNib()
setupView()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
self.setupView()
}
// Placeholder text indent
override func textRect(forBounds bounds: CGRect) -> CGRect {
return bounds.insetBy(dx: 20, dy: 5)
}
// Editing text indent
override func editingRect(forBounds bounds: CGRect) -> CGRect {
return bounds.insetBy(dx: 20, dy: 5)
}
func setupView() {
layer.cornerRadius = 25
layer.borderWidth = 2
layer.borderColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
clipsToBounds = true
textColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)
// Placeholder colour
attributedPlaceholder = NSAttributedString(string: placeholder!, attributes: [NSAttributedStringKey.foregroundColor: #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 1.0)])
}
}

//It will update both Simulator and InterfaceBuilder
import UIKit
#IBDesignable class ViewExtended: UIView {
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setupView()
}
func setupView() {
layer.borderColor = borderColor.cgColor
layer.borderWidth = borderWidth
layer.cornerRadius = cornerRadius
layer.shadowOpacity = shadowOpacity
layer.shadowRadius = shadowRadius
}
override func awakeFromNib() {
super.awakeFromNib()
setupView()
}
#IBInspectable var borderColor: UIColor = UIColor.red {
didSet {
layer.borderColor = borderColor.cgColor
setNeedsLayout()
}
}
#IBInspectable var borderWidth: CGFloat = 1.0 {
didSet {
layer.borderWidth = borderWidth
setNeedsLayout()
}
}
#IBInspectable var cornerRadius: CGFloat = 10.0 {
didSet {
layer.cornerRadius = cornerRadius
setNeedsLayout()
}
}
#IBInspectable var shadowColor: UIColor = UIColor.black {
didSet {
layer.borderColor = borderColor.cgColor
setNeedsLayout()
}
}
#IBInspectable var shadowOpacity: Float = 0.7 {
didSet {
layer.shadowOpacity = shadowOpacity
setNeedsLayout()
}
}
#IBInspectable var shadowRadius: CGFloat = 4.0 {
didSet {
layer.shadowRadius = shadowRadius
setNeedsLayout()
}
}
#IBInspectable var shadowOffset: CGSize = CGSize(width: 3, height: 3) {
didSet {
layer.shadowOffset = shadowOffset
setNeedsLayout()
}
}
}

Related

Incomprehensible work of the sublayer for cells in the CollectionView. Swift

So, the problem is that the gradient stroke is applied in a way that is not clear to me. At the same time, the problem is only when I do the logic of clicking on the cells as a radio button. If you leave the default (multiple choice), then there is no problem. Maybe somewhere I'm missing changing the height of the view on reloading the collection. Also, if I remove the gradient and include just a stroke, then everything works well. Who has any ideas?
I add the gradient directly in the cell.
class InvestorTypeCollectionViewCell: UICollectionViewCell {
#IBOutlet private weak var cellTitleLabel: UILabel!
#IBOutlet private weak var cellDescriptionLabel: UILabel!
#IBOutlet private weak var checkMarkImageView: UIImageView!
#IBOutlet private weak var itemContainerView: UIView!
weak var delegate: InvestorTypeCollectionViewCellDelegate?
override func prepareForReuse() {
super.prepareForReuse()
checkMarkImageView.image = UIImage(named: "uncheckedBox")
// remove sublayer
itemContainerView.layer.sublayers?.filter{ $0 is CAGradientLayer }.forEach{ $0.removeFromSuperlayer() }
}
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
setNeedsLayout()
layoutIfNeeded()
let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
var frame = layoutAttributes.frame
frame.size.height = ceil(size.height)
layoutAttributes.frame = frame
return layoutAttributes
}
func configCellWith(item: InvestorTypeModel, indexPath row: Int, selectedIndex: Int? = nil) {
itemContainerView.backgroundColor = UIColor.LIGHT_BLUE_BACKGROUND
itemContainerView.layer.cornerRadius = 8
cellTitleLabel.text = item.itemTitle.uppercased()
cellDescriptionLabel.text = Transformer.share.strippingOutHtmlFrom(text: item.itemDescription)
if item.checkBoxSelected {
diselectUISetUp()
// delegate to change item checkbox to false
delegate?.cellDidSelectedAt(indexPath: row, withCheckbox: false)
} else {
if let selectedIndex = selectedIndex {
if row == selectedIndex {
// select this cell
selectUISetUp()
// delegate to change item checkbox propertie to true
delegate?.cellDidSelectedAt(indexPath: row, withCheckbox: true)
}
}
}
}
private func diselectUISetUp() {
checkMarkImageView.image = UIImage(named: "uncheckedBox")
itemContainerView.layer.borderWidth = 0
itemContainerView.layer.borderColor = UIColor.clear.cgColor
itemContainerView.layer.cornerRadius = 8
}
private func selectUISetUp() {
checkMarkImageView.image = UIImage(named: "checkedBox")
// add gradient
let colors = [UIColor(red: 0.30, green: 0.84, blue: 0.74, alpha: 1.00),
UIColor(red: 0.44, green: 0.35, blue: 0.92, alpha: 1.00),
UIColor(red: 0.26, green: 0.20, blue: 0.87, alpha: 0.93)]
itemContainerView.gradientBorder(width: 1, colors: colors, andRoundCornersWithRadius: 8)
}
}
this is where the gradient is configured
func gradientBorder(width: CGFloat,
colors: [UIColor],
startPoint: CGPoint = CGPoint(x: 0.5, y: 0.0),
endPoint: CGPoint = CGPoint(x: 0.5, y: 1.0),
andRoundCornersWithRadius cornerRadius: CGFloat = 0) {
let existingBorder = gradientBorderLayer()
let border = existingBorder ?? CAGradientLayer()
border.frame = CGRect(x: bounds.origin.x, y: bounds.origin.y,
width: bounds.size.width + width, height: bounds.size.height + width)
border.colors = colors.map { return $0.cgColor }
border.startPoint = startPoint
border.endPoint = endPoint
let mask = CAShapeLayer()
let maskRect = CGRect(x: bounds.origin.x + width/2, y: bounds.origin.y + width/2,
width: bounds.size.width - width, height: bounds.size.height - width)
mask.path = UIBezierPath(roundedRect: maskRect, cornerRadius: cornerRadius).cgPath
mask.fillColor = UIColor.clear.cgColor
mask.strokeColor = UIColor.white.cgColor
mask.lineWidth = width
border.mask = mask
let exists = (existingBorder != nil)
if !exists {
layer.addSublayer(border)
}
}
private func gradientBorderLayer() -> CAGradientLayer? {
let borderLayers = layer.sublayers?.filter { return $0.name == UIView.kLayerNameGradientBorder }
if borderLayers?.count ?? 0 > 1 {
fatalError()
}
return borderLayers?.first as? CAGradientLayer
}
When the data arrives, I change the size of the collection
func refreshData() {
DispatchQueue.main.async {
self.collectionView.reloadData()
guard let dataCount = self.viewModelPresenter?.data?.count else { return }
self.heightConstraintCV.constant = 1000 + 50
}
}
You will find it much easier to use a subclassed UIView that handles its own gradient border.
For example:
#IBDesignable
class GradientBorderView: UIView {
// turns on/off the gradient border
#IBInspectable public var selected: Bool = false { didSet { setNeedsLayout() } }
// default colors
// - can be set at run-time if desired
public var colors: [UIColor] = [UIColor(red: 0.30, green: 0.84, blue: 0.74, alpha: 1.00),
UIColor(red: 0.44, green: 0.35, blue: 0.92, alpha: 1.00),
UIColor(red: 0.26, green: 0.20, blue: 0.87, alpha: 0.93)]
{
didSet {
setNeedsLayout()
}
}
// default boder line width, corner radius, and inset-from-edges
// - can be set at run-time if desired
#IBInspectable public var bWidth: CGFloat = 1 { didSet { setNeedsLayout() } }
#IBInspectable public var cRadius: CGFloat = 8 { didSet { setNeedsLayout() } }
#IBInspectable public var inset: CGFloat = 0.5 { didSet { setNeedsLayout() } }
override class var layerClass: AnyClass {
return CAGradientLayer.self
}
private var gLayer: CAGradientLayer {
return self.layer as! CAGradientLayer
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}
func commonInit() {
gLayer.startPoint = CGPoint(x: 0.5, y: 0.0)
gLayer.endPoint = CGPoint(x: 0.5, y: 1.0)
}
override func layoutSubviews() {
super.layoutSubviews()
let shapeLayer = CAShapeLayer()
if selected {
gLayer.colors = colors.compactMap( {$0.cgColor })
// make shapeLayer path the size of view inset by "inset"
// with rounded corners
// strokes are centered, so inset must be at least 1/2 of the border width
let mInset = max(inset, bWidth * 0.5)
shapeLayer.path = UIBezierPath(roundedRect: bounds.insetBy(dx: mInset, dy: mInset), cornerRadius: cRadius).cgPath
// clear fill color
shapeLayer.fillColor = UIColor.clear.cgColor
// stroke color can be any non-clear color
shapeLayer.strokeColor = UIColor.black.cgColor
shapeLayer.lineWidth = bWidth
} else {
// we'll mask with an empty path
shapeLayer.path = UIBezierPath().cgPath
}
gLayer.mask = shapeLayer
}
}
So, use a GradientBorderView instead of a UIView:
#IBOutlet private weak var itemContainerView: GradientBorderView!
and all you have to do is set its selected property to show/hide the border:
itemContainerView.selected = true
or you could set .isHidden to show/hide it.
The "gradient border" will automatically update any time the view size changes.
The view is also marked #IBDesignable with #IBInspectable properties, so you can see how it looks while designing in Storyboard (note: selected is false by default, so you won't see anything unless you change that to true).

Applying Gradient to button doesn't reflect in swift

I have written the following code and don't know what I'm doing wrong the button is not reflecting the gradient
I also tried calling my function under awakefromNib
class ButtonGradient: UIButton {
var color1 = #colorLiteral(red: 0.3411764801, green: 0.6235294342, blue: 0.1686274558, alpha: 1)
var color2 = #colorLiteral(red: 0.521568656, green: 0.1098039225, blue: 0.05098039284, alpha: 1)
var gradient = CAGradientLayer()
override init(frame: CGRect) {
super.init(frame: frame)
applyGradient()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
applyGradient()
}
func applyGradient() {
gradient.frame = self.bounds
gradient.colors = [color1,color2]
gradient.startPoint = CGPoint.zero
gradient.endPoint = CGPoint.init(x: 0.0, y: 0.5)
gradient.locations = [0,1]
self.layer.addSublayer(gradient)
}
}
I want to apply gradient vertically to my button.
It's pretty simple, here you are
#IBDesignable class GradientButton: UIButton {
#IBInspectable var topColor: UIColor = .white
#IBInspectable var bottomColor: UIColor = .black
override class var layerClass: AnyClass {
return CAGradientLayer.self
}
override func layoutSubviews() {
(layer as? CAGradientLayer)?.colors = [topColor.cgColor, bottomColor.cgColor]
}
}
Just change class from UIButton to GradientButton

Title not showing on UIButton Gradient View

I have a gradient class attached to my UIButton and the gradient shows fine. However, the title or text of the UIButton is not showing. It seems the gradient is covering the text. Heres my code:
#IBDesignable
class GradientView: UIButton {
#IBInspectable var topColor: UIColor = #colorLiteral(red: 1, green: 0.0318463631, blue: 0, alpha: 1) {
didSet {
self.setNeedsLayout()
}
}
#IBInspectable var bottomColor: UIColor = #colorLiteral(red: 1, green: 0.4265971184, blue: 0, alpha: 1) {
didSet {
self.setNeedsLayout()
}
}
override func layoutSubviews() {
let gradientLayer = CAGradientLayer()
gradientLayer.colors = [topColor.cgColor, bottomColor.cgColor]
gradientLayer.startPoint = CGPoint(x: 0, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 1, y: 0.5)
gradientLayer.frame = self.bounds
gradientLayer.cornerRadius = layer.cornerRadius
self.layer.insertSublayer(gradientLayer, at: 0)
}
//Rounded Button Functions
#IBInspectable var cornerRadius : CGFloat = 3.0 {
didSet {
self.layer.cornerRadius = cornerRadius
}
}
override func awakeFromNib() {
self.setupView()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
self.setupView()
}
func setupView() {
self.layer.cornerRadius = cornerRadius
}
#IBInspectable var border : CGFloat = 1.0 {
didSet {
self.layer.borderWidth = border
}
}
#IBInspectable var borderColor: UIColor? {
get {
return UIColor(cgColor: layer.borderColor!)
}
set {
layer.borderColor = newValue?.cgColor
}
}
}
I don't know what the problem is. I used this code for another project and it showed fine.
Thanks
You forgot to call super.layoutSubviews() in the layoutSubviews().
override func layoutSubviews() {
super.layoutSubviews()
// your code
}

Add Shadow and Corners to UIView except the Bottom

I want to add rounded corners to top left and top right and shadow around it except the bottom. There should be no shadow at bottom.
I am able to achieve rounded corners as needed. But not shadow. I need a code where both is achieved . In below image look at the Diagnose view. It has top left and top right corner rounded and shadow around it.
Try This Code.
Custom Method. Swift 4.0
#IBOutlet weak var myView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
customCornerWithShadow(myView: myView, cornerRadius: 20)
}
func customCornerWithShadow(myView:UIView,cornerRadius:CGFloat) {
myView.layer.cornerRadius = cornerRadius
myView.clipsToBounds = false[enter image description here][1]
myView.layer.maskedCorners = CACornerMask(rawValue: CACornerMask.RawValue(UInt8(CACornerMask.layerMinXMinYCorner.rawValue) | UInt8(CACornerMask.layerMaxXMinYCorner.rawValue)))
myView.layer.shadowColor = #colorLiteral(red: 0.3098039329, green: 0.01568627544, blue: 0.1294117719, alpha: 1)
myView.layer.shadowOffset = CGSize(width:0, height:-1)
let shadowPath = UIBezierPath(roundedRect: myView.bounds, cornerRadius: cornerRadius)
myView.layer.shadowPath = shadowPath.cgPath
myView.layer.shadowOpacity = 1
}
#IBOutlet var btnActive : UIButton!
override func viewDidLoad() {
super.viewDidLoad()
// btnActive.backgroundColor = UIColor(red: 171, green: 178, blue: 186, alpha: 1.0)
// Shadow and Radius
btnActive.layer.shadowColor = UIColor(red: 255, green: 255, blue: 255, alpha: 1).cgColor
btnActive.layer.shadowOffset = CGSize(width: 0.0, height: 2.0)
btnActive.layer.shadowOpacity = 2.0
btnActive.layer.shadowRadius = 5.0
btnActive.layer.masksToBounds = false
btnActive.layer.cornerRadius = 4.0
}
Found the solution :
clipsToBounds = true, makes corners round but shadow gets hidden.
so we can use 2 views one as container and the main view as its subview . Container will have clipstobound = false and the main view will have clipstobounds true.
let containerV = UIView(frame: CGRect(x: 0, y: 0, width: self.frame.size.width , height: 50))
containerV.clipsToBounds = false
containerV.layer.shadowColor = UIColor.black.cgColor
containerV.layer.shadowOpacity = 1
containerV.layer.shadowOffset = CGSize(width: -0.5, height: -3.0)
/* since we dont want shadow at bottom */
containerV.layer.shadowRadius = 2
containerV.layer.shadowPath = UIBezierPath(roundedRect: containerV.bounds,
cornerRadius: 10).cgPath
let headerLabel = UILabel()
headerLabel.frame = containerV.bounds
headerLabel.text = "Test Header"
headerLabel.backgroundColor = UIColor.white
headerLabel.clipsToBounds = true
headerLabel.layer.cornerRadius = 10
if #available(iOS 11.0, *) {
headerLabel.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
} else {
// Fallback on earlier versions
}
containerV.addSubview(headerLabel)
You Can Use extension,
in Swift 4.1 and Xcode 9.3.1
extension UIView {
#IBInspectable
var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
}
}
#IBInspectable
var borderWidth: CGFloat {
get {
return layer.borderWidth
}
set {
layer.borderWidth = newValue
}
}
#IBInspectable
var borderColor: UIColor? {
get {
if let color = layer.borderColor {
return UIColor(cgColor: color)
}
return nil
}
set {
if let color = newValue {
layer.borderColor = color.cgColor
} else {
layer.borderColor = nil
}
}
}
#IBInspectable
var shadowRadius: CGFloat {
get {
return layer.shadowRadius
}
set {
layer.shadowRadius = newValue
}
}
#IBInspectable
var shadowOpacity: Float {
get {
return layer.shadowOpacity
}
set {
layer.shadowOpacity = newValue
}
}
#IBInspectable
var shadowOffset: CGSize {
get {
return layer.shadowOffset
}
set {
layer.shadowOffset = newValue
}
}
#IBInspectable
var shadowColor: UIColor? {
get {
if let color = layer.shadowColor {
return UIColor(cgColor: color)
}
return nil
}
set {
if let color = newValue {
layer.shadowColor = color.cgColor
} else {
layer.shadowColor = nil
}
}
}
}

How to set the custom border color of UIView programmatically?

I am trying to set the custom border color of UIView programmatically in Swift.
If you Use Swift 2.0+
self.yourView.layer.borderWidth = 1
self.yourView.layer.borderColor = UIColor(red:222/255, green:225/255, blue:227/255, alpha: 1).cgColor
In Swift 4 you can set the border color and width to UIControls using below code.
let yourColor : UIColor = UIColor( red: 0.7, green: 0.3, blue:0.1, alpha: 1.0 )
yourControl.layer.masksToBounds = true
yourControl.layer.borderColor = yourColor.CGColor
yourControl.layer.borderWidth = 1.0
< Swift 4, You can set UIView's border width and border color using the below code.
yourView.layer.borderWidth = 1
yourView.layer.borderColor = UIColor.red.cgColor
Use #IBDesignable and #IBInspectable to do the same.
They are re-useable, easily modifiable from the Interface Builder and the changes are reflected immediately in the Storyboard
Conform the objects in the storyboard to the particular class
Code Snippet:
#IBDesignable
class CustomView: UIView{
#IBInspectable var borderWidth: CGFloat = 0.0{
didSet{
self.layer.borderWidth = borderWidth
}
}
#IBInspectable var borderColor: UIColor = UIColor.clear {
didSet {
self.layer.borderColor = borderColor.cgColor
}
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
}
}
Allows easy modification from Interface Builder:
You can write an extension to use it with all the UIViews eg. UIButton, UILabel, UIImageView etc.
You can customise my following method as per your requirement, but I think it will work well for you.
extension UIView{
func setBorder(radius:CGFloat, color:UIColor = UIColor.clearColor()) -> UIView{
var roundView:UIView = self
roundView.layer.cornerRadius = CGFloat(radius)
roundView.layer.borderWidth = 1
roundView.layer.borderColor = color.CGColor
roundView.clipsToBounds = true
return roundView
}
}
Usage:
btnLogin.setBorder(7, color: UIColor.lightGrayColor())
imgViewUserPick.setBorder(10)
Swift 5.2, UIView+Extension
extension UIView {
public func addViewBorder(borderColor:CGColor,borderWith:CGFloat,borderCornerRadius:CGFloat){
self.layer.borderWidth = borderWith
self.layer.borderColor = borderColor
self.layer.cornerRadius = borderCornerRadius
}
}
You used this extension;
yourView.addViewBorder(borderColor: #colorLiteral(red: 0.6, green: 0.6, blue: 0.6, alpha: 1), borderWith: 1.0, borderCornerRadius: 20)
swift 3
func borderColor(){
self.viewMenuItems.layer.cornerRadius = 13
self.viewMenuItems.layer.borderWidth = 1
self.viewMenuItems.layer.borderColor = UIColor.white.cgColor
}
We can create method for it. Simply use it.
public func createBorderForView(color: UIColor, radius: CGFloat, width: CGFloat = 0.7) {
self.layer.borderWidth = width
self.layer.cornerRadius = radius
self.layer.shouldRasterize = false
self.layer.rasterizationScale = 2
self.clipsToBounds = true
self.layer.masksToBounds = true
let cgColor: CGColor = color.cgColor
self.layer.borderColor = cgColor
}
Swift 3.0
groundTrump.layer.borderColor = UIColor.red.cgColor
Write the code in your viewDidLoad()
self.view.layer.borderColor = anyColor().CGColor
And you can set Color with RGB
func anyColor() -> UIColor {
return UIColor(red: 0.0/255.0, green: 0.0/255.0, blue: 0.0/255.0, alpha: 1.0)
}
Learn something about CALayer in UIKit
swift 3.0
self.uiTextView.layer.borderWidth = 0.5
self.txtItemShortDes.layer.borderColor = UIColor(red:205.0/255.0, green:205.0/255.0, blue:205.0/255.0, alpha: 1.0).cgColor
Swift 5*
I, always use view extension to make view corners round, set border color and width and it has been the most convenient way for me. just copy and paste this code and controlle these properties in attribute inspector.
extension UIView {
#IBInspectable
var cornerRadius: CGFloat {
get {
return layer.cornerRadius
}
set {
layer.cornerRadius = newValue
}
}
#IBInspectable
var borderWidth: CGFloat {
get {
return layer.borderWidth
}
set {
layer.borderWidth = newValue
}
}
#IBInspectable
var borderColor: UIColor? {
get {
if let color = layer.borderColor {
return UIColor(cgColor: color)
}
return nil
}
set {
if let color = newValue {
layer.borderColor = color.cgColor
} else {
layer.borderColor = nil
}
}
}
}
if you are dealing with the layers you can give border like this....
if not sometime you might have to true the wantslayer like self.anytextField.wantslayer = true
var BackgroundColor : CGColor = UIColor.blue.cgColor
subLayer.shadowColor = self.BackgroundColor
subLayer.borderColor = self.BackgroundColor
subLayer.borderWidth = CGFloat(4)
or you can use the extension of CA Layer for macOS
func addBorder(edge: NSRectEdge, color: NSColor, thickness: CGFloat) {
let border = CALayer()
switch edge {
case NSRectEdge.maxY:
border.frame = CGRect(x: 0, y: 0, width: frame.width, height: thickness)
case NSRectEdge.minY:
border.frame = CGRect(x:0, y: frame.height - thickness, width: frame.width, height:thickness)
case NSRectEdge.minX:
border.frame = CGRect(x:0, y:0, width: thickness, height: frame.height)
case NSRectEdge.maxX:
border.frame = CGRect(x: frame.width - thickness, y: 0, width: thickness, height: frame.height)
default: do {}
}
border.backgroundColor = color.cgColor
addSublayer(border)
}
its usage is given below
subLayer.addBorder(edge: <#T##NSRectEdge#>, color: <#T##NSColor#>, thickness: <#T##CGFloat#>)

Resources