2017-04-16 21 views
1

私にはわかりづらいデザイン要素があります。誰かが私を正しい方向に向けることができると願っています。私が構築しようとしている要素はそうです。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 

次に、私はrectを囲むようにストロークを描くために次の方法を使用しています。

// 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

コード(必要に応じて変更します。私はここでそのdrawコードのような形状を描く明確なのUIViewを使用):

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

完全に働きました!ありがとう、@マット!私はこの方法をあまりにも過度に複雑にしていた。私は '.clear'ブレンドモードでストロークできるとは思いませんでした。今や意味をなさない! – ZbadhabitZ

+0

丸い矩形を描く前にクリップする別の方法があります。多分私はそれを示していたはずです。 – matt

+0

2番目の方法でクリッピングを示すコードを追加しました。私は実際にこのケースではより良いクリッピングが好きです。制御が簡単です。 – 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

関連する問題