์๋ ํ์ธ์ ์ ์ธ์ ๋๋ค~!
UI ๊ตฌํ์ ๊ดํ ๊ฒ์๊ธ์ ์ฒ์ ์ ๋ก๋ ํ๋ ๊ฒ ๊ฐ์๋ฐ์,
๋ณต์กํ UI๋ฅผ ๊ตฌํํ๋ฉด์ ๊ฒช์๋ ๋ฌธ์ ๋ค ํน์ ๊ณ ๋ฏผํ๋ ์ ์ ๋ธ๋ก๊ทธ์๋ ๊ธฐ๋ก์ผ๋ก ๋จ๊ฒจ๋์์ผ๋ฉด ์ข์์ ๊ฑธ,, ํ๋ ์๊ฐ์
์์ ํ๋ก์ ํธ์์ ๊ฝค๋ ๊ณ ๋ฏผํ๋ ๊ณผ์ ์ ํฌ์คํ ํ๋ ค๊ณ ํฉ๋๋ค..! (๊ณต์ ํ๋ฉด ์ข์ผ๋๊น์..ใ )
์์ผ๋ก๋ ์ด์ ํด๊ฒฐ์ ๋ํ ๋ด์ฉ๋ ํฌ์คํ ์ ํด๋ณด๋๋ก ๋ ธ๋ ฅํ๊ฒ ์ต๋๋ค!
๋ณต์กํ ๋ชจ์์ ๋ง์คํฌ๋ฅผ ์ด๋ฏธ์ง์ ์ ์ฉํ๊ธฐ
์ด๋ฒ ํฌ์คํ ์์๋ ์ด๋ฏธ์ง์ ์ฌ๊ฐํ, ์์ฒ๋ผ ๊ฐ๋จํ ๋ํ์ด ์๋๋ผ ๋ณต์กํ ๋ชจ์์ ๋ง์คํฌ๋ฅผ ์ ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ํด ๊ณต์ ํด๋ณด๊ฒ ์ต๋๋ค!!
์์ ์ ์ฐธ์ฌํ์๋ ํ๋ก์ ํธ์์ ์๋น์ค์ ์ฌ๋ณผ์ธ ๋ง์๋ฉ๋ก ๋ชจ์์ด ์ฌ๋ฌ ํ๋ฉด์์ ๋ณด์์ต๋๋ค.
ํนํ, ๋ง์๋ฉ๋ก ๋ชจ์์ ๋ง์คํฌ๊ฐ ์ ์ฉ๋ ์ด๋ฏธ์ง๊ฐ ํ๋กํ ์ฌ์ง์ผ๋ก ์ ์ฉ๋์ด ์ฑ ๊ณณ๊ณณ์์ ์์ฃผ ์ฌ์ฉ๋์์ต๋๋ค.
์๋ ์๋๊ณ .. ์ฌ๊ฐํ๋ ์๋๊ณ .. ์ธ๋ชจ๋ ์๋๊ณ .. ๋ง์๋ฉ๋ก ๋ชจ์์ ๋์ฒด ์ด๋ป๊ฒ ๋ง์คํฌ๋ก ์ ์ฉํ๋!!!
๊ธฐํ, ๋์์ธ ํ์๋ค์๊ฒ ์ต๋ํ ๊ตฌํํด๋ณด๊ฒ ๋ค๊ณ ์ ๋ฌํ๊ณ ๊ตฌํ ๋ฐฉ๋ฒ์ ๋ํด ๊ณ ๋ฏผํ์ต๋๋ค.
๊ณ ๋ฏผ ๊ณผ์
๊ฐ์ฅ ๋จผ์ ๋ ์ค๋ฅธ ๋ฐฉ๋ฒ์ CALayer์ mask ํ๋กํผํฐ๋ฅผ ์ด์ฉํ๋ ๊ฒ์ด์์ต๋๋ค.
๊ณต์๋ฌธ์์ ์ค๋ช ์ ๋ฐ๋ฅด๋ฉด,
CALayer์ mask๋ ์ต์ ๋ ๋ ์ด์ด๋ก ๋ ์ด์ด์ ์ปจํ ์ธ ์ ๋ง์คํฌ๋ฅผ ์์ฐ๋๋ฐ ์ฌ์ฉ๋๋ ์ํ ์ฑ๋์ ๋๋ค.
๋ ์ด์ด์ ์ํ ์ฑ๋์ ๋ ์ด์ด์ ์ฝํ ์ธ ์ ๋ฐฐ๊ฒฝ ์ค ์ด๋ ์ ๋๋ฅผ ๋ณด์ฌ์ค์ง๋ฅผ ๊ฒฐ์ ํฉ๋๋ค.
์ ์ฒด ๋๋ ๋ถ๋ถ์ ์ผ๋ก ๋ถํฌ๋ช ํ ํฝ์ ์ ๊ธฐ๋ณธ ์ฝํ ์ธ ๋ฅผ ๋ณด์ฌ์ฃผ์ง๋ง, ์์ ํ ํฌ๋ช ํ ํฝ์ ์ ํด๋น ์ฝํ ์ธ ๋ฅผ ์ฐจ๋จํฉ๋๋ค.
์ด๋ค ๋ถ๋ถ์ ์ ์ธํ๊ณ ๋ณด์ฌ์ฃผ๊ณ ์ถ์ ๋, ๊ทธ ๋ถ๋ถ์ ํฌ๋ช ์ฒ๋ฆฌํด์ ๊ฐ๋ฆฌ๊ณ ๋ณด์ฌ์ค ์ ์๊ฒ ์ฌ์ฉํ ์ ์๋ Layer ๊ณ์ธต ์ ๋๋ก ํด์ํ ์ ์์ผ๋ฏ๋ก maskedImage๋ฅผ ๋ง๋๋ ๋ฐ ์ด์ฉํ ์ ์์ ๊ฒ์ด๋ผ๊ณ ํ๋จํ์ต๋๋ค!
๊ทธ๋ฐ๋ฐ, ์ฌ์ฉ ๋ฐฉ๋ฒ์ ๋ํด ์ฐพ์๋ณด๋ CALayer์ mask์ CAShapeLayer ์ธ์คํด์ค๋ฅผ ์ฃผ์ ํ์ฌ ๋ง์คํน์ ๊ตฌํํด์ผ ํ๊ณ ,
์ด ๋, CAShapeLayer์ path์ UIBezierPath๋ฅผ ํ์ฉํด ์ง์ ์ํ๋ ๋ชจ์์ path๋ฅผ ๊ทธ๋ ค์ ๋ฃ์ด์ค์ผ ํ๋ค๋ ๊ฒ์ด ๋ฌธ์ ์์ต๋๋ค.. (๋ง์๋ฉ๋ก ๋ชจ์์ ์ด๋ป๊ฒ ๋๊ฐ์ด ๊ทธ๋ ค์..๐ฅฒ)
ํ์ง๋ง, mask์ ๋ํด ์ฐพ์๋ณด๋ฉด์ UIView์๋ mask๋ผ๋ ํ๋กํผํฐ๊ฐ ์๋ค๋ ๊ฒ์ ๋ฐ๊ฒฌํ์ต๋๋ค.
๊ณต์ ๋ฌธ์์ ์ค๋ช ์ ๋ณด๋ฉด, CALayer์ mask์ ๋์ผํ ์ญํ ์ ํ๋๋ฐ, ํด๋น ํ๋กํผํฐ๋ ๋ ์ด์ด๊ฐ ์๋๋ผ ๋ทฐ์ด๋ค! ๋ผ๋ ์ฐจ์ด๋ง ์กด์ฌํ๋ ๊ฒ์ ํ์ธ ํ ์ ์์์ต๋๋ค.
๋ทฐ์ ์ฝํ ์ธ ๋ฅผ ๋ง์คํนํ๋ ๋ฐ ์ํ ์ฑ๋์ ์ฌ์ฉํ๋ ์ ํ์ ๋ทฐ ์ ๋๋ก ํด์ํ ์ ์์ ๊ฒ ๊ฐ์๋ฐ,,
๊ทธ๋ ๋ค๋ฉด UIImageView ๋ํ UIView๋ฅผ ์์ํ๊ณ ์์ผ๋ ์ด mask ํ๋กํผํฐ์ ์ํ๋ ์ด๋ฏธ์ง๋ฅผ ๋ฃ์ด ๋ง์คํน์ ํ ์ ์์ง ์์๊น..?
ํ๋ ์์ด๋์ด๊ฐ ๋ ์ฌ๋์ต๋๋ค.
์ด๋ฌํ ์์ด๋์ด๋ก ๊ด๋ จ ์๋ฃ๋ฅผ ๋ ์ฐพ์ ์ํ๋ maskedImage๋ฅผ ๊ตฌํํ ์ ์์์ต๋๋ค.
๊ตฌํ ๋ฐฉ๋ฒ
maskedImage Custom Class
class PomeMaskedImageView: UIImageView {
// MARK: Properties
private var maskImageView = UIImageView()
var maskImage: UIImage? {
didSet {
maskImageView.image = maskImage
updateImageView()
}
}
// MARK: Life Cycle
override func layoutSubviews() {
super.layoutSubviews()
updateImageView()
}
// MARK: Custom Methods
/// ์๋ณธ ์ด๋ฏธ์ง์ mask๋ฅผ ์ ์ฉํด์ฃผ๋ ๋ฉ์๋
private func updateImageView() {
guard let image = maskImageView.image else {
return
}
maskImageView.frame = bounds
mask = maskImageView
}
}
๋ง์คํฌ๊ฐ ์์์ง ์ด๋ฏธ์ง๊ฐ ํ๋ฉด ๊ณณ๊ณณ์์ ์ฌ์ฉ๋๊ธฐ ๋๋ฌธ์ ์์ ๊ฐ์ด Custom Class๋ก ์ ์ํด๋๊ณ ์ฌ๋ฌ ์ด๋ฏธ์ง์ ๋ง์คํฌ๋ฅผ ์ ์ฉํ ์ ์๋๋ก ๊ตฌํํ์ต๋๋ค.
์์ ์ฝ๋๋ฅผ ์ดํด๋ณด๊ฒ ์ต๋๋ค!
<ํ๋กํผํฐ>
- maskImageView: ๋ง์คํฌ๋ก ์ฌ์ฉ๋ ์ด๋ฏธ์ง๋ทฐ
- maskImage: ๋ง์คํฌ๋ก ์ฌ์ฉ๋ ์ด๋ฏธ์ง (๋ง์๋ฉ๋ก ๋ชจ์ ์ด๋ฏธ์ง) - ์ธ๋ถ์์ ์ด๋ฏธ์ง๋ฅผ ์ง์ ํด์ฃผ๊ธฐ ์ํด public์ผ๋ก ์ ์ธ
<๋ฉ์๋>
updateImageView()
์๋ณธ ์ด๋ฏธ์ง์ mask๋ฅผ ์ ์ฉํด์ฃผ๋ ๋ฉ์๋์ ๋๋ค.
๋ง์คํฌ๋ก ์ฌ์ฉ๋ ์ด๋ฏธ์ง(maskImageView.image)๊ฐ nil์ด ์๋๋ผ๋ฉด ,
maskImageView์ frame์ PomeMaskedImageView์ bounds์ ๋ง์ถฅ๋๋ค. (๋ง์คํฌ๊ฐ ์๋ณธ์ด๋ฏธ์ง ์์ ์ ํํ ๊ฒน์ณ์ ธ ์ํ๋ ๋ถ๋ถ๋ง ๋ณด์ฌ์ง ์ ์๋๋ก ํ๊ธฐ ์ํจ)
๊ทธ๋ฐ ๋ค์, PomeMaskedImageView์ mask ํ๋กํผํฐ์ maskImageView๋ฅผ ํ ๋นํฉ๋๋ค.
didSet ํ๋กํผํฐ ์ต์ ๋ฒ ์ฌ์ฉ ์ด์ ?
didSet ํ๋กํผํฐ ์ต์ ๋ฒ๋ maskImage์ ์๋ก์ด ๊ฐ์ด ์ค์ ๋ ๋๋ง๋ค ํธ์ถ๋ฉ๋๋ค. (์ธ๋ถ์์ ๋ง์คํฌ ์ด๋ฏธ์ง์ ๊ฐ์ด ํ ๋น๋ ๋๋ง๋ค)
didSet ๋ธ๋ก ์์์๋ maskImageView์ image๋ฅผ ์๋ก์ด maskImage๋ก ์ค์ ํ๊ณ , updateImageView() ๋ฅผ ํธ์ถํด ์ด๋ฏธ์ง ๋ทฐ์ ๋ง์คํฌ๋ฅผ ์ ์ฉํฉ๋๋ค.
layoutSubviews()์์ updateImageView() ํธ์ถ ์ด์ ?
updateImageView() ๋ฉ์๋ ์์์ ๋ง์คํฌ๊ฐ ์ ํ์ด ์๋ณธ ์ด๋ฏธ์ง ์์ ๊ฒน์ณ์ง๋๋ก ํด์ฃผ๊ธฐ ์ํด์๋, ๋ง์คํนํ๋ ค๋ ๋ทฐ(์๋ณธ ์ด๋ฏธ์ง)์ bounds ๊ฐ์ ๋ํ ์ ๋ณด๊ฐ ํ์ํฉ๋๋ค.
๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ๋ฐํ์ ๋์์ bounds ๊ฐ์ด ์๋ก ๊ณ์ฐ๋๊ณ ์ ์ฉ๋๋ ๊ฒ์ ์ ์ ์๋ layoutSubviews()์์ ํด๋น ๋ฉ์๋๋ฅผ ํธ์ถํ์ฌ ๋ทฐ์ ๋ ์ด์์์ด ๋ณ๊ฒฝ๋ ๋๋ง๋ค ๋ง์คํฌ ์ด๋ฏธ์ง์ frame์ ๊ฐฑ์ ํ์ฌ ํญ์ ์ฌ๋ฐ๋ฅธ ํฌ๊ธฐ์ ์์น์ ๋ง์คํฌ๊ฐ ์ ์ฉ๋ ์ ์๋๋ก ํ๋ ์์ ์ด ํ์ํฉ๋๋ค.
์ฐธ๊ณ ) layoutSubviews() ๋ฉ์๋๋ ๋ทฐ์ ๋ ์ด์์์ด ๋ณ๊ฒฝ๋ ๋๋ง๋ค ์๋์ผ๋ก ํธ์ถ๋๋ ๋ฉ์๋ ์ธ๋ฐ, ์ด ๋๋ง๋ค ๋ทฐ์ bounds์ frame์ด ์๋ก ๊ณ์ฐ๋๊ณ ์ ์ฉ๋ฉ๋๋ค.
์ฌ์ฉํ๋ ๊ณณ
private let profileImageView = PomeMaskedImageView().then {
$0.image = UIImage(named: "userProfileEmpty160") // ์๋ณธ ์ด๋ฏธ์ง
$0.maskImage = UIImage(named: "userProfileEmpty160") // ๋ง์คํฌ๋ก ์ฌ์ฉํ ์ด๋ฏธ์ง
}
์ฌ์ฉํ๋ ๊ณณ์์๋ ์์ ๊ฐ์ด ์๋ณธ ์ด๋ฏธ์ง์ ๋ง์คํฌ๋ก ์ฌ์ฉํ ์ด๋ฏธ์ง๋ฅผ ํ ๋นํด์ฃผ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค!
๊ฒฐ๊ณผ ํ๋ฉด
[์ฐธ๊ณ ์๋ฃ]
https://stackoverflow.com/questions/5757386/how-can-i-mask-a-uiimageview
'๐ iOS > iOS' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[iOS] fastlane์ ์ด์ฉํด ๋ฐฐํฌ ์๋ํํ๊ธฐ (6) | 2024.09.06 |
---|---|
[iOS] TDD์ Unit Test (3) | 2023.12.14 |
[iOS] iOS ํ์ผ ์์คํ (1) | 2023.11.28 |
[iOS] ํค์ฒด์ธ(Keychain)์ ์ด์ฉํ ๋ฐ์ดํฐ ์ ์ฅ ๋ฐ ๊ด๋ฆฌ (0) | 2023.08.06 |
[iOS/Architecture] Coordinator Pattern (2) | 2022.12.11 |