2017-04-16 153 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