2022.10.19 (์)
A path that consists of straight and curved line segments that you can render in your custom views.
view์์ ๋ ๋๋งํ ์ ์๋ ์ง์ ๊ณผ ๊ณก์ ์ผ๋ก ๊ตฌ์ฑ๋ ๊ฒฝ๋ก์ ๋๋ค. ์ด ํด๋์ค๋ view์ ํํ๋ฅผ ์ง์ ๊ทธ๋ ค์ฃผ๊ธฐ ์ํด์ ์ฌ์ฉํฉ๋๋ค. ๊ณก์ , ์์นํ, ์ง์ ํ ๋ฑ์ผ๋ก ๋ชจ์์ ์ ์ํด์ค ํ, ํ์ฌ ๊ทธ๋ ค์ง๋ context์ ๋ ๋๋งํ๊ธฐ ์ํด ์ถ๊ฐ์ ์ธ ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
UIBezierPath ๊ฐ์ฒด๋ ๋ ๋๋ง๋ ๋ ๊ฒฝ๋ก๋ฅผ ์ค๋ช ํ๋ ์์ฑ๋ค๊ณผ ์ง์ค๋ฉํธ๋ฆฌ์ ๊ฒฝ๋ก๋ค์ ํฉ์นฉ๋๋ค. ์ฆ, ์ง์ค๋ฉํธ๋ฆฌ ๋ฐ ์์ฑ์ ๊ฐ๋ณ์ ์ผ๋ก ์ค์ ํ๊ณ ์๋ก ๋ ๋ฆฝ์ ์ผ๋ก ๋ณ๊ฒฝํ ์ ์์ต๋๋ค. ๊ฐ์ฒด๋ฅผ ์ํ๋ ๋ฐฉ์์ผ๋ก ๊ตฌ์ฑํ ํ์๋ ํ์ฌ context์์ ๊ฐ์ฒด๋ฅผ ๊ทธ๋ฆฌ๋๋ก ์ง์ ํ ์ ์์ต๋๋ค. ์์ฑ, ๊ตฌ์ฑ ๋ฐ ๋ ๋๋ง ํ๋ก์ธ์ค๋ ๋ชจ๋ ๋ณ๊ฐ์ ๋จ๊ณ๋ก Bezier ๊ฒฝ๋ก ๊ฐ์ฒด๋ฅผ ์ฝ๋์์ ์ฝ๊ฒ ์ฌ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋์ผํ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ ๋์ผํ ๋ํ์ ์ฌ๋ฌ๋ฒ ๋ ๋๋งํ ์๋ ์์ผ๋ฉฐ, ์ฐ์ ๊ทธ๋ฆฌ๊ธฐ ํธ์ถ๊ฐ์ ๋ ๋๋ง์ต์ ์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
๊ฒฝ๋ก์ ํ์ฌ ์ง์ ์ ์กฐ์ํ์ฌ ๊ฒฝ๋ก์ ์ง์ค๋ฉํธ๋ฆฌ๋ฅผ ์ค์ ํฉ๋๋ค. ๋น ๊ฒฝ๋ก ๊ฐ์ฒด๋ฅผ ์๋ก ๋ง๋ค๋ฉด ํ์ฌ ์ ์ด ์ ์๋์ง ์์ผ๋ฏ๋ก ๋ช ์์ ์ผ๋ก ์ค์ ํด์ผํฉ๋๋ค. ์ธ๊ทธ๋จผํธ๋ฅผ ๊ทธ๋ฆฌ์ง ์๊ณ ํ์ฌ ์ ์ ์ด๋ํ๋ ค๋ฉด move(to:) ํจ์๋ฅผ ์ฌ์ฉํฉ๋๋ค. ๋ค๋ฅธ ๋ชจ๋ ํจ์๋ ๊ฒฝ๋ก์ ์ ๋๋ ์ปค๋ธ ์ธ๊ทธ๋จผํธ๋ฅผ ์ถ๊ฐํฉ๋๋ค. ์๋ก์ด ์ธํฌ๋จผํธ๋ฅผ ์ถ๊ฐํ๋ ๋ฐฉ๋ฒ์ ํญ์ ํ์ฌ ์ง์ ์์ ์์ํ์ฌ ์ง์ ํ ์ ์ง์ ์์ ๋๋๋ ๊ฒ์ผ๋ก ๊ฐ์ ํฉ๋๋ค. ์ธ๊ทธ๋จผํธ๋ฅผ ์ถ๊ฐํ๋ฉด ์ธ๊ทธ๋จผํธ์ ๋์ ์ด ์๋์ผ๋ก ํ์ฌ ํฌ์ธํธ๊ฐ ๋ฉ๋๋ค.
ํ๋์ Bezier ๊ฒฝ๋ก ๊ฐ์ฒด๋ ์ด๋ ค์๊ฑฐ๋ ๋ซํ ํ์ ๊ฒฝ๋ก๊ฐ ์ผ๋ง๋ ์ง ํฌํจ๋ ์ ์์ต๋๋ค. ๊ฐ ํ์ ๊ฒฝ๋ก๋ ์ฐ๊ฒฐ๋ ์ผ๋ จ์ ๊ฒฝ๋ก ์ธ๊ทธ๋จผํธ๋ฅผ ๋ํ๋ ๋๋ค. close() ํจ์๋ฅผ ํธ์ถํ๋ฉด ํ์ฌ ํฌ์ธํธ์์ ํ์ ๊ฒฝ๋ก์ ์ฒซ ๋ฒ์งธ ํฌ์ธํธ๊น์ง ์ง์ ์ธ๊ทธ๋จผํธ๊ฐ ์ถ๊ฐ๋์ด ํ์ ๊ฒฝ๋ก๊ฐ ๋ซํ๋๋ค. move(to:) ํจ์๋ฅผ ํธ์ถํ๋ฉด ํ์ฌ ํ์ ๊ฒฝ๋ก๊ฐ ์ข ๋ฃ๋๊ณ (๋ซ์ง ์๊ณ ) ๋ค์ ํ์ ๊ฒฝ๋ก์ ์์์ ์ด ์ค์ ๋ฉ๋๋ค. Bezier ๊ฒฝ๋ก ๊ฐ์ฒด์ ํ์ ๊ฒฝ๋ก๋ ๋์ผํ ๋๋ฉด ํน์ฑ์ ๊ณต์ ํ๋ฏ๋ก ๊ทธ๋ฃน์ผ๋ก ์กฐ์ํด์ผํฉ๋๋ค. ์๋ก ๋ค๋ฅธ ํน์ฑ์ ๊ฐ์ง ํ์ ๊ฒฝ๋ก๋ฅผ ๊ทธ๋ฆฌ๋ ค๋ฉด ๊ฐ ํ์ ๊ฒฝ๋ก๋ฅผ ์์ฒด UIBezierPath๊ฐ์ฒด์ ๋ฃ์ด์ผํฉ๋๋ค.
Bezier ๊ฒฝ๋ก์ ์ง์ค๋ฉํธ๋ฆฌ ๋ฐ ์์ฑ์ ๊ตฌ์ฑํ ํ์๋ stoke() ์ fill() ํจ์๋ฅผ ์ฌ์ฉํ์ฌ ํ์ฌ ๊ทธ๋ํฝ context์์ ๊ฒฝ๋ก๋ฅผ ๊ทธ๋ฆฝ๋๋ค. stoke() ํจ์๋ ํ์ฌ stroke ์์๊ณผ Bezier๊ฒฝ๋ก ๊ฐ์ฒด์ ์์ฑ์ ์ฌ์ฉํ์ฌ ๊ฒฝ๋ก์ ์ค๊ณฝ์ ์ ๊ทธ๋ฆฝ๋๋ค. ๋ง์ฐฌ๊ฐ์ง๋ก fill() ํจ์๋ ํ์ฌ ์์ ์ฌ์ฉํ์ฌ ๊ฒฝ๋ก๋ก ๋๋ฌ์ธ์ธ ์์ญ์ ์ฑ์๋๋ค.
Bezier ๊ฒฝ๋ก ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ ๋ํ์ ๊ทธ๋ฆด๋ฟ๋ง ์๋๋ผ ์ ์๋ฅด๊ธฐ ์์ญ์ ์ ์ํ ์ ์์ต๋๋ค. addClip() ํจ์๋ ๊ฒฝ๋ก ๊ฐ์ฒด๋ก ํํ๋ ๋ํ์ ๊ทธ๋ํฝ ์ปจํ ์คํธ์ ํ์ฌ clipping ์์ญ๊ณผ ๊ต์ฐจํฉ๋๋ค. ์๋ก์ด ๊ต์ฐจ๋ก ์์ญ ๋ด์ ์๋ ์ฝํ ์ธ ๋ง ๊ทธ๋ํฝ์ ๋ ๋๋ง๋ฉ๋๋ค.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let bview: BezierView = .init(frame: view.frame)
bview.backgroundColor = .clear
view.addSubview(bview)
}
}
class BezierView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(_ rect: CGRect) {}
}
BezierPath๋ฅผ ์ด๊ธฐํํ๋ ๋ฒ์ ์ฌ๋ฌ๊ฐ์ง๊ฐ ์์ต๋๋ค.
์ฌ๊ฐํ
override func draw(_ rect: CGRect) {
let path = UIBezierPath(rect: CGRect(x: bounds.midX-50, y:bounds.midY-50, width: 100, height: 100))
UIColor.systemRed.setFill()
UIColor.systemYellow.setStroke()
path.lineWidth = 10
path.stroke()
path.fill()
}
ํ์ํ
override func draw(_ rect: CGRect) {
let path = UIBezierPath(ovalIn: CGRect(x: bounds.midX-100, y:bounds.midY-100, width: 200, height: 300))
UIColor.blue.setFill()
UIColor.red.setStroke()
path.lineWidth = 10
path.stroke()
path.fill()
}
๋ฅ๊ทผ ์ฌ๊ฐํ
override func draw(_ rect: CGRect) {
let path = UIBezierPath(roundedRect: CGRect(x: bounds.midX-100, y:bounds.midY-100, width: 100, height: 200), cornerRadius: 20)
UIColor.blue.setFill()
UIColor.red.setStroke()
path.lineWidth = 10
path.stroke()
path.fill()
}
์์นํ
override func draw(_ rect: CGRect) {
let path = UIBezierPath(roundedRect: CGRect(x: bounds.midX-50, y:bounds.midY-50, width: 100, height: 100), byRoundingCorners: [.topLeft,.topRight], cornerRadii: .init(width: 50, height: 50))
UIColor.blue.setFill()
UIColor.red.setStroke()
path.lineWidth = 10
path.stroke()
path.fill()
}
๊ณก์
override func draw(_ rect: CGRect) {
let path = UIBezierPath(arcCenter: center, radius: 50, startAngle: 0, endAngle: .pi, clockwise: false)
UIColor.blue.setFill()
UIColor.red.setStroke()
path.lineWidth = 10
path.stroke()
path.fill()
}
Initializer ์ ๋ฆฌ
init(rect: CGRect)
init(ovalIn: CGRect)
init(roundedRect: CGRect, cornerRadius: CGFloat)
init(roundedRect: CGRect, byRoundingCorners: UIRectCorner, cornerRadii: CGSize)
init(arcCenter: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat, clockwise: Bool)
- clockwise: ๊ทธ๋ ค์ง ๋ฐฉํฅ ์ ํ (false: ์, true: ์๋)
์์ ๊ฐ์ด Initializer์ ํตํด ๋ชจ์์ ๋ง๋ค ์ ์์ง๋ง ์ง์ ์ํ๋ ๋ชจ์์ ๊ทธ๋ฆด ์ ์์ต๋๋ค.
override func draw(_ rect: CGRect) {
let path = UIBezierPath()
path.move(to: center)
path.addCurve(to: .init(x: center.x + 100, y: center.y - 100),
controlPoint1: .init(x: center.x + 1, y: center.y - 97),
controlPoint2: .init(x: center.x + 82, y: center.y - 7))
path.addLine(to: .init(x: center.x + 100, y: center.y))
path.addLine(to: .init(x: center.x, y: center.y))
UIColor.blue.setFill()
UIColor.red.setStroke()
path.lineWidth = 10
path.stroke()
path.fill()
path.close() // ๋ชจ์์ด ์์ฑ๋๋ฉด ๋๊ธฐ
}
func move(to: CGPoint)
- ์์์ ์ ์ ํ ์ ์์ต๋๋ค.
- ํ์ฌ point๋ฅผ ์ง์ ํด์ค๋๋ค.
func addLine(to: CGPoint)
func addArc(withCenter: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat, clockwise: Bool)
func addCurve(to: CGPoint, controlPoint1: CGPoint, controlPoint2: CGPoint)
- 3์ฐจ ๋ฒ ์ง์ด ๊ณก์ ๊ทธ๋ฆฌ๊ธฐ
func addQuadCurve(to: CGPoint, controlPoint: CGPoint)
- 2์ฐจ ๋ฒ ์ง์ด ๊ณก์ ๊ทธ๋ฆฌ๊ธฐ
๊ณก์ ์ ๊ทธ๋ฆด ๋ ์ฐธ๊ณ ํ ๋งํ ์ฌ์ดํธ https://cubic-bezier.com/#.17,.67,.83,.67
path.stroke()
๋ฅผ ์ด์ฉํด์ ๊ฐ์ฅ์๋ฆฌ(ํ ๋๋ฆฌ)๋ฅผ ๊ทธ๋ฆด ์ ์์ต๋๋ค.path.lineWidth = 10
์ ์ด์ฉํด์ ์ ์ ๋๊ป๋ฅผ ์ ํ ์ ์์ต๋๋ค.setStroke()
๋ฅผ ์ด์ฉํด์ ์ํ๋ ์ ์๊น์ ์ ํ ์ ์์ต๋๋ค.path.lineCapStyle = .round
๋ฅผ ์ด์ฉํ๋ฉด ์ ์ ๋์ ์ด ๋ฅ๊ธ์ด ์ง๋๋ค. (์์๊ณผ ๋์๋ง ์ ์ฉ)path.lineJoinStyle = .round
๋ฅผ ์ด์ฉํ๋ฉด ๋ชจ๋ ๋ชจ์๋ฆฌ๊ฐ ๋ฅ๊ธ์ด ์ง๋๋ค.path.fill()
์ ํตํด ์์ ์ฑ์์ค๋๋ค.