iOS 응용 (swift)
[iOS - swift] 1. CALayer 마스킹 활용 - 마스킹하는 방법 (layer.mask, .evenOdd)
jake-kim
2023. 2. 12. 17:33
1. CALayer 마스킹 활용 - 마스킹하는 기본 방법 (mask, .evenOdd)<
2. CALayer 마스킹 활용 - 특정 뷰 음영 효과 주는 방법
마스킹 기초 개념
- UIView마다 CALayer를 가지고 있고, 이 CALayer의 프로퍼티인 mask에 CAShapeLayer 인스턴스를 주입하면 마스킹이 구현됨
- 마스킹이라는것은 의미 그대로 가리는 것 (= 지금 UIView의 마스킹된 영역을 없애고 뒤에있는 뷰가 보이도록 하는 것)
- CAShapeLayer의 path정보를 입력받아야 하는데, 이 path는 UIBezierPath로 직접 path 정보를 주고 그릴 수 있고, 사각형 같은 경우는 addRect(_:)를하여 쉽게 사용이 가능
(마스킹 기초 코드)
extension UIView {
func mask(rect: CGRect, reversal: Bool) {
// 1. path 인스턴스로 경로 정보 획득
let path = CGMutablePath()
// TODO
// 2. CAShapeLayer 인스턴스에 위 path 인스턴스 사용
let shapeLayer = CAShapeLayer()
// TODO
// 3. mask에 shapeLayer 인스턴스 사용
layer.mask = shapeLayer
}
}
마스킹 예제
* 예제에 나온 코드는 코드로 UI 작성의 편의를 위해 SnapKit 사용
- 마스킹 예제를 위해 뷰 준비
- view위에 UIImageView를 addSubview한 상태
import UIKit
import SnapKit
class ViewController: UIViewController {
private let imageView = UIImageView(image: UIImage(named: "blog"))
override func viewDidLoad() {
super.viewDidLoad()
imageView.contentMode = .scaleAspectFill
view.addSubview(imageView)
imageView.snp.makeConstraints {
$0.edges.equalToSuperview()
}
}
}

- 마스킹사용이 쉽게하기위해 extension으로 구현
extension UIView {
func mask(rect: CGRect) {
// 1. path 인스턴스로 경로 정보 획득
let path = CGMutablePath()
path.addRect(rect)
// 2. CAShapeLayer 인스턴스에 위 path 인스턴스 사용
let shapeLayer = CAShapeLayer()
shapeLayer.path = path
// 3. mask에 shapeLayer 인스턴스 사용
layer.mask = shapeLayer
}
}
- 마스킹 적용
- 주의할점) path로 채운 부분이 보여지는 것이고 그 외의 공간은 사라지게 하는 것
imageView.mask(rect: .init(x: 150, y: 120, width: 80, height: 80))

CAShapeLayer의 fillMode
- CAShapeLayer의 fillMode라는 프로퍼터가 있는데, fillMode를 .evenOdd로 설정
- .evenOdd란? path가 중복으로 path된 곳만 마스킹한다는 의미
.evenOdd로 지정한 부분을 마스킹 처리하기
- .evenOdd는 중복으로 path된 곳을 마스킹하므로, mask(rect:) 메소드 수정
- isRectMasking 파라미터를 사용하여 분기문 추가
- path로 전체 영역을 그리고, 지정한 부분을 한번 더 그리면 중복으로 그려진 부분만 마스킹 되도록 구현
- .evenOdd로 설정
extension UIView {
func mask(rect: CGRect, isRectMasking: Bool) {
// 1. path 인스턴스로 경로 정보 획득
let path = CGMutablePath()
if isRectMasking {
let allRect = CGRect(x: 0, y: 0, width: frame.size.width, height: frame.size.height)
path.addRect(allRect)
}
path.addRect(rect)
// 2. CAShapeLayer 인스턴스에 위 path 인스턴스 사용
let shapeLayer = CAShapeLayer()
shapeLayer.path = path
if isRectMasking {
shapeLayer.fillRule = .evenOdd
}
// 3. mask에 shapeLayer 인스턴스 사용
layer.mask = shapeLayer
}
}
(결과)

* 전체코드: https://github.com/JK0369/ExCALayer_0
* 참고
https://developer.apple.com/documentation/quartzcore/cashapelayerfillrule/1521843-evenodd