Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to draw a dash line border for NSView

Tags:

objective-c

In my custom view, i have code as below:

- (void)drawRect:(NSRect)dirtyRect {
    [super drawRect:dirtyRect];

     //Drawing code here.
    [self setWantsLayer: YES];
    [self.layer setBorderWidth: 1];

    [self.layer setBorderColor:[NSColor colorWithRed:205/255.0 green:211/255.0 blue:232/255.0 alpha:1.0].CGColor];
    [self.layer setCornerRadius: 10];
}

This is OK to set border line and color for my NSView, but i want to set a dash line, anyone know how to do this? And i tried some codes from the web search, but it doens't draw a border at all.

- (void)drawRect:(NSRect)dirtyRect {
    [super drawRect:dirtyRect];

    // Drawing code here.
    CGFloat dashPattern[] = {10,4}; //make your pattern here
    NSBezierPath *textViewSurround = [NSBezierPath bezierPathWithRoundedRect:self.frame xRadius:10 yRadius:10];
    [textViewSurround setLineWidth:2.0f];
    [textViewSurround setLineDash:dashPattern count:2 phase:0];
    [[NSColor colorWithRed:205/255.0 green:211/255.0 blue:232/255.0 alpha:1.0] set];
    [textViewSurround stroke];
}
like image 862
jimwan Avatar asked Jan 31 '26 21:01

jimwan


2 Answers

here is a complete example using a subclass of NSView in Swift 3:

class BorderedView: NSView {
    override func draw(_ dirtyRect: NSRect) {
        super.draw(dirtyRect)

        // dash customization parameters
        let dashHeight: CGFloat = 3
        let dashLength: CGFloat = 10
        let dashColor: NSColor = .red

        // setup the context
        let currentContext = NSGraphicsContext.current()!.cgContext
        currentContext.setLineWidth(dashHeight)
        currentContext.setLineDash(phase: 0, lengths: [dashLength])
        currentContext.setStrokeColor(dashColor.cgColor)

        // draw the dashed path
        currentContext.addRect(bounds.insetBy(dx: dashHeight, dy: dashHeight))
        currentContext.strokePath()
    }
}
like image 167
Casey Avatar answered Feb 02 '26 17:02

Casey


In case you want to setup line border with CAShapeLayer (Swift 4.2):

class StrokeWithDashedLineView: NSView {

   private let shapeLayer = CAShapeLayer()
   private let fillLayer = CALayer()
   private let textLabel = NSTextField().autolayoutView()

   override init(frame frameRect: NSRect) {
      super.init(frame: frameRect)
      setupUI()
      setupLayout()
   }

   required init?(coder decoder: NSCoder) {
      fatalError()
   }

   override var intrinsicContentSize: NSSize {
      return CGSize(intrinsicHeight: 76)
   }

   override func layout() {
      super.layout()
      updateLayers()
   }

   private func updateLayers() {
      layer?.cornerRadius = 0.5 * bounds.height // Making ourselves rounded.

      // Stroke Layer
      let shapeBounds = CGRect(width: bounds.width - shapeLayer.lineWidth, height: bounds.height - shapeLayer.lineWidth)
      let shapeRadius = 0.5 * shapeBounds.height
      let path = CGMutablePath()
      path.addRoundedRect(in: shapeBounds, cornerWidth: shapeRadius, cornerHeight: shapeRadius)
      shapeLayer.path = path
      shapeLayer.bounds = shapeBounds
      shapeLayer.position = CGPoint(x: 0.5 * shapeLayer.lineWidth, y: 0.5 * shapeLayer.lineWidth)

      // Fill Layer
      let fillBounds = CGRect(width: bounds.width - 2 * shapeLayer.lineWidth, height: bounds.height - 2 * shapeLayer.lineWidth)
      fillLayer.cornerRadius = 0.5 * fillBounds.height
      fillLayer.bounds = fillBounds
      fillLayer.position = CGPoint(x: shapeLayer.lineWidth, y: shapeLayer.lineWidth)
   }

   private func setupUI() {
      wantsLayer = true
      layer?.masksToBounds = true

      shapeLayer.lineWidth = 3
      shapeLayer.strokeColor = NSColor.red.cgColor
      shapeLayer.fillColor = nil
      shapeLayer.lineDashPattern = [11.2, 11.2]
      shapeLayer.lineCap = .round
      shapeLayer.anchorPoint = .zero

      fillLayer.backgroundColor = NSColor.yellow.cgColor
      fillLayer.anchorPoint = .zero

      layer?.addSublayer(shapeLayer)
      layer?.addSublayer(fillLayer)

      addSubview(textLabel)

      textLabel.text = "Drag Xib or Storyboard files onto\nthis window to open them"
      textLabel.alignment = .center
      textLabel.textColor = .black
      textLabel.font = NSFont.semibold(size: 13)
      textLabel.isEditable = false
      textLabel.drawsBackground = false
      textLabel.isBezeled = false
   }

   private func setupLayout() {
      textLabel.centerXAnchor.constraint(equalTo: centerXAnchor).activate()
      textLabel.centerYAnchor.constraint(equalTo: centerYAnchor).activate()
   }
}

Result:

Window with CAShapeLayer

like image 31
Vlad Avatar answered Feb 02 '26 16:02

Vlad