Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
Tags
- swiftUI
- rxswift
- 스위프트
- 리펙토링
- UICollectionView
- clean architecture
- Xcode
- Protocol
- 리팩토링
- ribs
- tableView
- 애니메이션
- uiscrollview
- SWIFT
- Refactoring
- ios
- Human interface guide
- 리펙터링
- Clean Code
- Observable
- swift documentation
- HIG
- RxCocoa
- map
- 클린 코드
- uitableview
- collectionview
- MVVM
- combine
- UITextView
Archives
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] CALayer masking 마스킹 (UIBezierPath, CAShapeLayer) 본문
iOS 응용 (swift)
[iOS - swift] CALayer masking 마스킹 (UIBezierPath, CAShapeLayer)
jake-kim 2022. 4. 14. 22:00
마스킹 구현 아이디어
- 파란색 UIView의 layer.mask에 CAShapeLayer() 인스턴스를 주입하여, 안에가 비어지도록 구현
- CAShapeLayer 인트선스의 path에는 와인딩 룰을 가지고 있는 UIBezierPath를 주입
사전 지식) UIBezierPath의 성질 - 와인딩 룰
- Winding Rules: path의 외부와 내부를 파악하는 방법 중 하나이며, path의 방향에 따라 내부를 칠하거나 비우는 규칙
- UIView의 path값을 UIBezierPath인스턴스로 만든 후, UIView의 mask에 넣으면 와인딩 룰에 의하여 안쪽 color를 채워주는 방법
- path가 겹치는 부분들의 내부 색상은 CAShapeLayer의 "fillColor"프로퍼티, path의 색상은 "strokeColor"로 설정
- 이 성질을 이용하여 복잡한 UI를 구현하는 내용은 Apple 문서 참고
mask 구현 방법
- UIBeizerPath는 마스킹하려는 뷰의 bounds값을 알아야하므로, 런타임 동안에 bounds값이 정해지는것을 알 수있는layoutSubviews()안에서 UIBezierPath 인스턴스 생성하고 적용
- layoutSubviews를 재정의하기위해 커스텀 뷰 따로 정의
final class SampleView: UIView {
private enum Constants {
static let lineWidth = 2.0
static let cornerRadius = 10.0
}
init() {
super.init(frame: .zero)
self.backgroundColor = .systemBlue
}
required init?(coder: NSCoder) {
fatalError()
}
override func layoutSubviews() {
super.layoutSubviews()
// TODO:
}
}
- layoutSubviews() 안에서 구현
- CAShapeLayer를 통해 내부 색상(fillColor)를 clear로 놓고, lineWidth, cornerRadius 적용
- CAShapeLayer의 path에는 UIBezierPath 인스턴스를 주입
- layer.mask에 CAShapeLayer 주입
override func layoutSubviews() {
super.layoutSubviews()
let shapeLayer = CAShapeLayer()
shapeLayer.lineWidth = Constants.lineWidth
shapeLayer.cornerRadius = Constants.cornerRadius
shapeLayer.strokeColor = UIColor.black.cgColor
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.path = UIBezierPath(
roundedRect: self.bounds.insetBy(dx: Constants.lineWidth, dy: Constants.lineWidth),
cornerRadius: Constants.cornerRadius
).cgPath
self.layer.mask = shapeLayer
}
* UIBezierPath의 roundedRect에 insetBy(dx:dy:)를 쓰는 이유: 뷰에 늘어날 lineWidth만큼 마스킹 영역을 줄여야, 테두리가 잘리지 않고 제대로 표출
ex) insetBy(dx:dy:)없이 사용한 경우 - 테두리가 조금 잘린 형태
shapeLayer.path = UIBezierPath(
roundedRect: self.bounds // <- 기존 코드: self.bounds.insetBy(dx: Constants.lineWidth, dy: Constants.lineWidth),
cornerRadius: Constants.cornerRadius
).cgPath
* 전체 코드: https://github.com/JK0369/ExLayerMasking
* 참고
https://developer.apple.com/documentation/quartzcore/cashapelayer
'iOS 응용 (swift)' 카테고리의 다른 글
Comments