2017-04-16 217 views
1

我有一個設計元素,我很難搞清楚;希望有人能夠指引我走向正確的方向。我試圖建立的元素就像這樣;使用UIBezierPath繪製圓角使用UIBezierPath

Rounded Button With No Bottom Border

實際上,它是一個圓角矩形左側,頂部的行程,和右側(底部應該沒有中風)。

我已經涉足使用下面的代碼;

// Create the rounded rectangle 
let maskPath = UIBezierPath(roundedRect: myView.bounds, byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: 4.0, height: 4.0)) 

// Setup a shape layer 
let shape = CAShapeLayer() 

// Create the shape path 
shape.path = maskPath.cgPath 

// Apply the mask 
myView.layer.mask = shape 

隨後,我使用以下方法在矩形上繪製筆劃;

// Add border 
let borderLayer = CAShapeLayer() 
borderLayer.path = maskPath.cgPath 
borderLayer.fillColor = UIColor.clear.cgColor 
borderLayer.strokeColor = UIColor.white.cgColor 
borderLayer.lineWidth = 2.0 
borderLayer.frame = self.bounds 
self.layer.addSublayer(borderLayer) 

產生以下圖像;

Rounded Rect with Stroke

我已經無法找出如何可以卸下底部行程畫使用UIBezierPath()的項目,但在某種程度上四捨五入的角落,這將是相同的到圓角矩形(我在同一視圖中使用另一個圓角矩形用於不同的目的,並且圓角將需要相同)。

謝謝!

回答

2

請勿使用形狀圖層。使用圖層(或視圖)。繪製UIBezierPath的路徑並對其進行描邊,然後通過繪製並用.clear混合模式對其進行描邊來清除底線。

結果:

enter image description here

代碼(修改爲所需的;我在這裏使用一個明確的UIView繪製的形狀作爲其draw代碼):

let p = UIBezierPath(roundedRect: self.bounds, 
     byRoundingCorners: [.topLeft, .topRight], 
     cornerRadii: CGSize(width: 4.0, height: 4.0)) 
    UIColor.white.setStroke() 
    p.stroke() 
    let p2 = UIBezierPath() 
    p2.move(to: CGPoint(x:0, y:self.bounds.height)) 
    p2.addLine(to: CGPoint(x:self.bounds.width, y:self.bounds.height)) 
    p2.lineWidth = 2 
    p2.stroke(with: .clear, alpha: 1) 

EDIT另一種方法是在繪製圓角矩形之前一直要剪掉底線區域:

let p1 = UIBezierPath(rect: CGRect(origin:.zero, 
     size:CGSize(width:self.bounds.width, height:self.bounds.height-2))) 
    p1.addClip() 
    let p = UIBezierPath(roundedRect: self.bounds, 
     byRoundingCorners: [.topLeft, .topRight], 
     cornerRadii: CGSize(width: 4.0, height: 4.0)) 
    UIColor.white.setStroke() 
    p.stroke() 
+0

,完美的工作!謝謝,@matt!我太過於複雜了;我沒有意識到我可以用'.clear'混合模式進行中風。現在有道理! – ZbadhabitZ

+0

還有另一種方法,即在繪製圓角矩形之前剪切。也許我也應該證明這一點。 – matt

+0

添加代碼以演示第二種方式,裁剪。在這種情況下,我更喜歡裁剪。它更容易控制。 – matt

1

CGMutablePath方法addArc(tangent1End:tangent2End:radius:transform:)旨在輕鬆製作圓角。

extension CGMutablePath { 
    static func bottomlessRoundedRect(in rect: CGRect, radius: CGFloat) -> CGMutablePath { 
     let path = CGMutablePath() 
     path.move(to: CGPoint(x: rect.minX, y: rect.maxY)) 
     path.addArc(tangent1End: CGPoint(x: rect.minX, y: rect.minY), tangent2End: CGPoint(x: rect.maxX, y: rect.minY), radius: radius) 
     path.addArc(tangent1End: CGPoint(x: rect.maxX, y: rect.minY), tangent2End: CGPoint(x: rect.maxX, y: rect.maxY), radius: radius) 
     path.addLine(to: CGPoint(x: rect.maxX, y: rect.maxY)) 
     return path 
    } 
} 

一旦你的方法,最好使用自定義視圖來管理CAShapeLayer,因此它可以自動適應大小的變化。演示:

class MyFrameView: UIView { 
    override class var layerClass: AnyClass { return CAShapeLayer.self } 

    override func layoutSubviews() { 
     super.layoutSubviews() 
     let layer = self.layer as! CAShapeLayer 
     layer.lineWidth = 2 
     layer.strokeColor = UIColor.white.cgColor 
     layer.fillColor = nil 
     layer.path = CGMutablePath.bottomlessRoundedRect(in: bounds.insetBy(dx: 10, dy: 10), radius: 8) 
    } 
} 

import PlaygroundSupport 

let view = UIView(frame: CGRect(x: 0, y: 0, width: 120, height: 60)) 
view.backgroundColor = #colorLiteral(red: 0.7034167647, green: 0.4845994711, blue: 0.6114708185, alpha: 1) 
let frameView = MyFrameView(frame: view.bounds) 
frameView.autoresizingMask = [.flexibleWidth, .flexibleHeight] 
view.addSubview(frameView) 
let label = UILabel(frame: view.bounds) 
label.text = "Hello" 
label.textColor = .white 
label.textAlignment = .center 
view.addSubview(label) 

PlaygroundPage.current.liveView = view 

結果:

demo

+0

我很高興你添加了這個。我們以前常常在貝塞爾路徑有自動圓角之前這樣做!我沒有在這裏使用它的唯一原因是我想堅持OP開始的確切的貝塞爾路徑,因爲這是問題規定的一部分。 – matt