[iOS/UI] UIBezierPath ์์ Gradient ์ปฌ๋ฌ๋ก ์ฑ์ฐ๊ธฐ (Fill a UIBezierPath with Gradient Color)
์๋ ํ์ธ์ Foma๐ป ์ ๋๋ค!
์ค๋์ UIBezierPath ์์ Gradient ์ปฌ๋ฌ๋ก ์ฑ์ฐ๋ ๋ฐฉ๋ฒ์ ๋ํด์ ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
๋ฐ๋ก ์์ํ ๊ฒ์~
TestView
๋ทฐ๋ฅผ ์๋์ ๊ฐ์ด ์ด๊ธฐํ ํด์ค๋๋ค.
class TestView: 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) {
}
}
UIBezierPath
์ด์ UIBezierPath๋ฅผ draw ๋ฉ์๋ ์์ ๊ทธ๋ ค๋ณด๊ฒ ์ต๋๋ค.
ํ์ํ ๊ฒฝ๋ก๋ฅผ ์๋์ ๊ฐ์ด ์์ฑํด ์ค๋๋ค.
let path:UIBezierPath = UIBezierPath(ovalIn: CGRect(x: bounds.midX-50, y:bounds.midY-50, width: 100, height: 200))
CGGradient
UIBezierPath์ ๊ทธ๋ ๋์ธํธ ์์์ ์ ํ๊ธฐ ์ํด์ CGGradient ๊ฐ์ฒด๋ฅผ ์ด์ฉํด์ผ ํ๋๋ฐ์.
์ด ๊ฐ์ฒด์๋ 3๊ฐ์ง ํ๋ผ๋ฏธํฐ๊ฐ ํ์ํฉ๋๋ค.
1. ๊ทธ๋ ๋์ธํธ ์ปฌ๋ฌ๋ฅผ ์ฌ์ฉํ ๊ณต๊ฐ
๊ทธ๋ ๋์ธํธ ์ปฌ๋ฌ๋ฅผ ์ฌ์ฉํ ๊ณต๊ฐ์ CGColorSpace๋ผ๋ ํด๋์ค๋ฅผ ์ด์ฉํ๋๋ฐ์.
์ด๊ฒ์ ํ๋ฉด์ ํ์๋๋ ์์๊ฐ์ ํด์ํ๋ ํด๋์ค์ ๋๋ค.
ํฌ๊ฒ๋ RGB ์์ผ๋ก ํด์ํ ๊ฒ์ธ์ง, Gray๋ก ํด์ํ ๊ฒ์ธ์ง, CMYK๋ก ํด์ํ ๊ฒ์ธ์ง ๋ฑ์ด ์์ต๋๋ค.
์ด๋ฒ์ ์ ๋ ํด๋น ๋๋ฐ์ด์ค์ RGB ์์ ๊ณต๊ฐ์ ์ฌ์ฉํ๋๋ก ํ๊ฒ ์ต๋๋ค.
let colorSpace = CGColorSpaceCreateDeviceRGB()
2. ๊ทธ๋ ๋์ธํธ ์ปฌ๋ฌ๋ฅผ ์ด๋ฃฐ ์๋ค
๋ง ๊ทธ๋๋ ๊ทธ๋ ๋์ธํธ ์ปฌ๋ฌ๋ฅผ ์ด๋ฃฐ ์๋ค์ ์ ํด์ค๋๋ค.
์ ๋ ์๋์ ๊ฐ์ด ๋นจ๊ฐ์๊ณผ ํ๋์์ ์ด์ฉํด ๊ทธ๋ ๋์ธํธ ์ปฌ๋ฌ๋ฅผ ๊ตฌ์ฑํ๋๋ก ํ๊ฒ ์ต๋๋ค.
let gradientColors:[CGColor] = [UIColor.red.cgColor,UIColor.blue.cgColor]
3. ๊ทธ๋ ๋์ธํธ ์ปฌ๋ฌ์ ์์น๋ค
๋ง์ง๋ง์ผ๋ก ๊ทธ๋ ๋์ธํธ ์ปฌ๋ฌ์ ์์น๋ฅผ ์ ํด์ค์ผ ํ๋๋ฐ์.
์๋ค์ด ์ด๋ ์์น์ ์ง์ ๋ ๊ฒ์ธ์ง๋ฅผ 0๊ณผ 1์ ์ฌ์ฉํด ๋ํ๋ด ์ค๋๋ค. (ํ์ ๋ฐ๋์ CGFloat์ด์ด์ผ ํฉ๋๋ค.)
์๋ ์ฌ์ง์์ ๊ฐ์ฅ ์ผ์ชฝ์ด [1.0,0.0] ๊ฐ์ด๋ฐ๊ฐ [0.0,1.0] ์ค๋ฅธ์ชฝ์ด [0.5,0.5]๋ฅผ ์ ์ฉํ ๊ฒฐ๊ณผ์ ๋๋ค.
์ ๋ ์ปฌ๋ฌ ์์น๋ฅผ [0.0,1.0] ์ผ๋ก ์ง์ ํ๊ฒ ์ต๋๋ค.
let colorLocations: [CGFloat] = [0.0,1.0]
์ด๋ ๊ฒ 3๊ฐ์ง ํ๋ผ๋ฏธํฐ๋ฅผ ๋ชจ๋ ์ค์ ํ๋ค๋ฉด CGGradient ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด ์ค์ผ๊ฒ ์ฃ ?
์๋์ ๊ฐ์ด ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด ์ค๋๋ค.
let cgGradientColor = CGGradient(colorsSpace: colorSpace, colors: gradientColors as CFArray, locations:colorLocations)!
CGContext
์์์ UIBezierPath์ CGGradient๋ฅผ ์์ฑํด ์ฃผ์์ฃ ?
๊ทธ๋ ๋ค๋ฉด ๋ณธ๊ฒฉ์ ์ผ๋ก ํด๋น ์ ๋ณด๋ฅผ "๊ทธ๋ฆฌ๊ธฐ" ์์ํด์ผ ํ๋๋ฐ์.
Core Graphics์์ 2D๋ก ๋ฌด์์ธ๊ฐ๋ฅผ ๊ทธ๋ฆฌ๊ธฐ ์ํด์ CGContext๋ฅผ ์ง์ ํด ์ค์ผ ํฉ๋๋ค.
์ฝ๊ฒ ํ์ฌ ๊ทธ๋ํฝ์ ๋ง๊ฒ ์ปจํ ์คํธ๋ฅผ ์ง์ ํด ์ค ์ ์๋ ๋ฉ์๋๊ฐ ์กด์ฌํ๋๋ฐ
๋ฐ๋ก "UIGraphicsGetCurrentContext()"์ ๋๋ค.
ํด๋น ๋ฉ์๋๋ฅผ ํตํด์ ํ์ฌ ์ปจํ ์คํธ๋ฅผ ์์๋ด์ด ์ธํ ํด์ค ์ ์์ต๋๋ค.
let context = UIGraphicsGetCurrentContext()!
์ด์ ์ ์ปจํ ์คํธ์ ๋ณธ๊ฒฉ์ ์ผ๋ก ์ด๋ค ์์ผ๋ก ๊ทธ๋ฆด ๊ฒ์ธ์ง๋ฅผ ๋ช ๊ฐ์ง ์์ฑํด ์ฃผ์ด์ผ ํ๋๋ฐ์.
1. ๊ฒฝ๋ก ์ถ๊ฐํ๊ธฐ
์์์ ๋ง๋ UIBezierPath ๊ฒฝ๋ก๋ฅผ ํ์ฌ ์ปจํ ์คํธ์ ์ถ๊ฐํด ์ค๋๋ค.
context.addPath(path.cgPath)
2. ๊ฒฝ๋ก ์ง์ ํด ์ฃผ๊ธฐ
์์์ ์ถ๊ฐํด์ค ๊ฒฝ๋ก๋ฅผ clip() ๋ฉ์๋๋ฅผ ํตํด์ ํด๋ฆฌํํ ๊ฒฝ๋ก๋ฅผ ์์ ํ ์ ์๋๋ก ํฉ๋๋ค.
context.clip()
3. ๊ฒฝ๋ก์ ์ ๋๊ป ์ ํ๊ธฐ
๊ฒฝ๋ก์ ์ ๋๊ป๋ฅผ ์ด๋ ์ ๋๋ก ํ ๊ฒ์ธ์ง ์ธํ ํด ์ค๋๋ค.
context.setLineWidth(10)
4. ๊ฒฝ๋ก๋ฅผ stroke๋ก ๋์ฒดํ๋๋ก ํฉ๋๋ค.
UIBezierPath๋ฅผ ๊ทธ๋ฆฌ๋ stroke๋ฅผ ๊ฒฝ๋ก๋ก ์ง์ ํด ์ค๋๋ค.
context.replacePathWithStrokedPath()
๋ง์ฝ ์ง์ ํ์ง ์๋๋ค๋ฉด UIBezierPath ์์ ๊ทธ๋ ๋์ธํธ ์์ด fill๋ก ๋ฉ๋๋ค.
์ผ์ชฝ์ด ํด๋น ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ๊ฒ์ด๊ณ ์ค๋ฅธ์ชฝ์ด ์์ฑํ์ง ์์์ ๊ฒฝ์ฐ์ ๋๋ค.
6. ๊ทธ๋ ๋์ธํธ ๊ทธ๋ ค์ฃผ๊ธฐ
๋ง์ง๋ง์ผ๋ก ํ์ฌ ์ปจํ ์คํธ์ ์์ ์ธํ ํ๋ CGGradient ์ธ์คํด์ค์ ์์ ์ง์ ๊ณผ ๋ ์ง์ ์ ์ง์ ํด ์ค๋๋ค.
context.drawLinearGradient(cgGradientColor, start: CGPoint(x: 0, y: 0), end: CGPoint(x: frame.width, y:frame.height), options: [])
๊ทธ๋ ๋์ธํธ๋ฅผ ๊ทธ๋ฆฌ๋ ์ต์ ์ Linear๋ฟ๋ง ์๋๋ผ Radical ๋ฐฉ์์ผ๋ก๋ ๊ทธ๋ฆด ์ ์์ต๋๋ค.
TestViewController
TestView๋ฅผ ์์ ๊ฐ์ด ์ธํ ํด์ฃผ๊ณ TestViewController์์ ํ ์คํธํ๊ฒ ๋๋ฉด
class TestViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let testView:TestView = TestView(frame:view.frame)
testView.backgroundColor = .white
view.addSubview(testView)
}
}
์๋์ ๊ฐ์ด ์ง์ ํ UIBezierPath๋๋ก Gradient ์ปฌ๋ฌ๊ฐ ์ฑ์์ง๊ฒ ๋ฉ๋๋ค.
Source Code