이전에 view.layer.maskedCorners 를 사용하여 특정 코너에만 radius를 적용해 본 경험은 있었습니다. 하지만 이번에는 각각의 코너에 서로 다른 radius 값을 적용해야 할 일이 생겨서 방법을 찾아보았고, 그 방법을 기록 및 공유해보려 합니다.
그럼 예시로 아래와 같은 뷰를 구현해보겠습니다.
보통 특정 코너에 radius를 적용하기 위해 사용하는 maskedCorners 는 left-top, left-bottom 의 14 px 짜리 코너만 적용하거나, right-top, right-bottom 의 4 px 짜리 코너만 적용하는 등, 특정 코너에 하나의 radius 값만 적용할 수 있었습니다.
하지만 제가 구현해야 하는 뷰는 위에 보이는 뷰처럼 특정 코너에는 14 px 의 radius를, 나머지 코너에는 4 px 의 radius를 적용해야 했습니다. 따라서 하나의 radius 값이 아니라 여러 개의 radius 값을 적용할 수 있어야 했습니다.
그러기 위해서는 UIBezierPath 를 활용해야합니다.
(UIBezierPath에 대한 설명은 ZeddiOS 님 게시글을 보면 쉽게 이해할 수 있습니다.)
1. UIBezierPath 의 extension 으로 아래 코드를 작성합니다.
extension UIBezierPath {
convenience init(for bounds: CGRect, leftTopSize: CGSize = .zero, rightTopSize: CGSize = .zero, leftBottomSize: CGSize = .zero, rightBottomSize: CGSize = .zero) {
self.init()
let path = CGMutablePath()
let leftTop: CGPoint = bounds.origin
let rightTop: CGPoint = CGPoint(x: bounds.maxX, y: bounds.minY)
let leftBottom: CGPoint = CGPoint(x: bounds.minX, y: bounds.maxY)
let rightBottom: CGPoint = CGPoint(x: bounds.maxX, y: bounds.maxY)
if leftTopSize != .zero {
// 1️⃣
path.move(to: CGPoint(x: leftTop.x + leftTopSize.width, y: leftTop.y))
} else {
path.move(to: leftTop)
}
// path가 그려지는 순서가 leftTop -> rightTop -> rightBottom -> leftBottom -> leftTop 이므로 아래 조건문 순서가 바뀌어서는 안됩니다.
if rightTopSize != .zero {
// 2️⃣
path.addLine(to: CGPoint(x: rightTop.x - rightTopSize.width, y: rightTop.y))
// 3️⃣
path.addCurve(to: CGPoint(x: rightTop.x, y: rightTop.y + rightTopSize.height), control1: CGPoint(x: rightTop.x, y: rightTop.y), control2: CGPoint(x: rightTop.x, y: rightTop.y + rightTopSize.height))
} else {
path.addLine(to: rightTop)
}
if rightBottomSize != .zero {
// 4️⃣
path.addLine(to: CGPoint(x: rightBottom.x, y: rightBottom.y - rightBottomSize.height))
// 5️⃣
path.addCurve(to: CGPoint(x: rightBottom.x - rightBottomSize.width, y: rightBottom.y), control1: CGPoint(x: rightBottom.x, y: rightBottom.y), control2: CGPoint(x: rightBottom.x - rightBottomSize.width, y: rightBottom.y))
} else {
path.addLine(to: rightBottom)
}
if leftBottomSize != .zero {
// 6️⃣
path.addLine(to: CGPoint(x: leftBottom.x + leftBottomSize.width, y: leftBottom.y))
// 7️⃣
path.addCurve(to: CGPoint(x: leftBottom.x, y: leftBottom.y - leftBottomSize.height), control1: CGPoint(x: leftBottom.x, y: leftBottom.y), control2: CGPoint(x: leftBottom.x, y: leftBottom.y - leftBottomSize.height))
} else {
path.addLine(to: leftBottom)
}
if leftTopSize != .zero {
// 8️⃣
path.addLine(to: CGPoint(x: leftTop.x, y: leftTop.y + leftTopSize.height))
// 9️⃣
path.addCurve(to: CGPoint(x: leftTop.x + leftTopSize.width, y: leftTop.y), control1: CGPoint(x: leftTop.x, y: leftTop.y), control2: CGPoint(x: leftTop.x + leftTopSize.width, y: leftTop.y))
} else {
path.addLine(to: leftTop)
}
path.closeSubpath()
cgPath = path
}
}
위의 코드를 좀 더 쉽게 이해할 수 있도록 각 스텝별로 아래에 그림을 그려보았습니다.
이렇게 코드를 실행하게 되면 left-top 👉 right-top 👉 right-bottom 👉 left-bottom 👉 left-top 의 순서대로 선을 그리게 됩니다. (코드 순서에 따라 그려지는 순서도 다르게 할 수 있습니다)
2. 그럼 이제 UIView 의 extension 으로 아래 코드를 작성합니다.
extension UIView {
func roundCorners(leftTop: CGFloat = 0, rightTop: CGFloat = 0, leftBottom: CGFloat = 0, rightBottom: CGFloat = 0) {
let leftTopSize = CGSize(width: leftTop, height: leftTop)
let rightTopSize = CGSize(width: rightTop, height: rightTop)
let leftBottomSize = CGSize(width: leftBottom, height: leftBottom)
let rightBottomSize = CGSize(width: rightBottom, height: rightBottom)
let maskedPath = UIBezierPath(for: self.bounds, leftTopSize: leftTopSize, rightTopSize: rightTopSize, leftBottomSize: leftBottomSize, rightBottomSize: rightBottomSize)
let shape = CAShapeLayer()
shape.path = maskedPath.cgPath
self.layer.mask = shape
}
}
이렇게 되면 UIView의 레이어에 각각의 corner radius 가 적용된 UIBezierPath가 mask로 적용되어집니다.
사용하는 코드쪽에서는 아래처럼 작성하여 사용할 수 있습니다.
그리고 만약 이 UIView 에 border 도 적용하고 싶다면 아래처럼 따로 코드를 추가 작성해주어야 합니다. 기존에 border를 추가하듯 layer.borderWidth 만 설정해주면 적용되지 않습니다.
'iOS > iOS' 카테고리의 다른 글
Swift 에서 선언된 enum을 Objc 코드에서 사용하기 (2) | 2023.03.13 |
---|---|
[Apple] userInteractionEnabled (0) | 2023.02.24 |
[Objective-C] 기본문법 (함수, 변수) (0) | 2022.01.13 |
Objective-C 와 Swift 혼용 사용하기 (2) | 2022.01.13 |
Displaying a Bottom Sheet in iOS 15 Using UISheetPresentationController (0) | 2021.07.11 |
댓글