본문 바로가기
iOS/iOS

UIView의 각 코너마다 서로 다른 radius 적용하기

by 헤콩 2022. 4. 19.
반응형

이전에 view.layer.maskedCorners 를 사용하여 특정 코너에만 radius를 적용해 본 경험은 있었습니다. 하지만 이번에는 각각의 코너에 서로 다른 radius 값을 적용해야 할 일이 생겨서 방법을 찾아보았고, 그 방법을 기록 및 공유해보려 합니다.

 

그럼 예시로 아래와 같은 뷰를 구현해보겠습니다.

 

보통 특정 코너에 radius를 적용하기 위해 사용하는 maskedCornersleft-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 만 설정해주면 적용되지 않습니다.

이미지뷰 결과

 

 

 

 

 

 

 

 

Different cornerRadius for each corner Swift 3 - iOS

I want to set different corner radius for a view in Swift -3 , I am able to set the radius for the each corner to the same value like the one mentioned in the following post ,how to set cornerRadiu...

stackoverflow.com

반응형

댓글