[iOS] Layer Masking - CALayer.mask 일부만 보여주기

2021. 5. 5. 16:51iOS

반응형

이번에 UI를 구현하면서 부분적으로 제외해서 보여주어야 하는 구현 내용이 있었는데요.

보통 cornerRadius 값과 clipsToBounds 같은 값들을 활용해서 둥글게 보이는 화면을 표현하고는 했었습니다.

 

그러나 이번에는 둥근 화면 뿐 아니라 모퉁이의 둥근 부분도 표현해야했기 때문에, 조금 구현내용이 달랐습니다..!!

 

여기서 어떤 방법을 사용했는지 알아보도록하겠습니다.

 

CALayermask라는 값을 활용해서 해결했는데요.

애플에서 설명하는 것을 보면 다음과 같습니다.

레이어의 내용을 마스크하는데 투명 채널을 사용되는 옵셔널 레이어라고 합니다.
제가 이해한 내용으로는 어떤 부분을 제외하고 보여주고 싶을 때, 그 부분을 투명처리해서 가리고 보여줄 수 있게 사용할 수 있는 Layer 계층인 것 같습니다.

 

이렇게만 설명으로 봐서는 어떻게 동작하는지 잘 감이 오시지 않을 수 있지만..!! 

간단한 예시를 같이 해보면서 알아보겠습니다.

현재 이런 화면을 보여주어야하는 구현 사항이 있습니다. 

그렇다면, 보통은 cornerRadius, clipsToBounds를 사용해서 할 수 있겠죠?! 

하지만 우리는 CALayer.mask를 활용할거에요 :)

먼저 저 동그란 화면을 보여주기 위해 네모난 UIView의 컴포넌트가 필요합니다.

이 뷰를 활용해서 바깥 부분을 제외한 부분을 보여줄 것입니다. 

 

이 화면을 둥글게 만들기 위한 절차는 다음과 같아요~!

  1. 원형의 크기에 맞는 CGRect를 생성
  2. 원형에 맞는 UIBezierPath를 생성
  3. UIBezierPath를 활용해서 CAShapeLayer 생성
  4. mask에 CAShapeLayer 지정

이렇게 하면, 해당 CAShapeLayer에 모양으로 뜬 부분을 제외하고는 바깥 부분은 가려지게 됩니다.

코드로 볼게요.

@IBOutlet weak var rectView: UIView!

override func viewDidLoad() {
    super.viewDidLoad()
    
    // 1
    let bounds = self.rectView.bounds
    
    // 2
    let pathCircle = UIBezierPath(ovalIn: bounds)
    
    // 3
    let layer = CAShapeLayer()
    layer.path = pathCircle.cgPath
    
    // 4
    rectView.layer.mask = layer
}

이렇게 지정해주면 아마 네모난 화면이 동그랗게 잘려서 보이는 효과를 볼 수 있을거에요 :)

 

그럼 이러한 mask를 활용해서 더 복잡한 바깥 레이어를 따보도록하겠습니다.

그림이 조금 이상하지만 왼쪽 오른쪽의 사이드만 둥글고 가운데 부분에 툭 튀어나온 둥근 부분을 표현해야하는 상황입니다.

이 그림을 표현하기 위해서는 우선 제일 위에 있는 둥근 부분까지의 높이를 가진 UIView가 하나 필요합니다.

여기서 저희는 아까 UIBezierPath를 활용해서 다음과 같이 Path들을 추가해 mask에 넣어주고 이외의 부분들은 안보이게 처리할 것입니다. 

 

그럼 이번에는 좀 더 크게 UIView를 만들어서 저런 모양을 만들어보겠습니다~

높이와 넓이는 300으로 지정해서 진행했는데요. 여기서 원은 반지름 50, 사각형의 높이는 250만큼 잘리게해서 250+50으로 300의 높이를 맞춰주도록 할거에요..!! 

 

한 번 코드로 바로 따라가볼게요.

@IBOutlet weak var rectView: UIView!

override func viewDidLoad() {
    super.viewDidLoad()
    
    let totalPath = UIBezierPath()

    let height: CGFloat = 250
    
    let rectangleRect = CGRect(x: 0, y: rectView.bounds.height - height, width: rectView.bounds.width, height: height)
    let rectanglePath = UIBezierPath(roundedRect: rectangleRect, byRoundingCorners: [.topLeft, .topRight], cornerRadii: CGSize(width: 15, height: 15))

    let ovalRect = CGRect(x: (sampleView.bounds.width / 2) - 50, y: 0, width: 100, height: 100)
    let ovalPath = UIBezierPath(ovalIn: ovalRect)

    totalPath.append(ovalPath)
    totalPath.append(rectanglePath)

    let maskLayer = CAShapeLayer()
    maskLayer.path = totalPath.cgPath
    rectView.layer.mask = maskLayer
}

이렇게 해당 원에 해당하는 UIBezierPath, 네모에 해당하는 UIBezierPath를 생성해서 종합적인 Path를 생성해서 mask에 대입해주면 좀 더 복잡한 마스킹을 적용할 수 있게됩니다..!!

 

이렇게 하면 어떤 화면이 나올까요?

바로 다음과 같이 아까 약간 허접(?)하게 그렸던 그림이 완성된 것을 알 수 있습니다 :)

이렇게 오늘은 잘 사용안 할 수도 있지만 mask를 이용해서 바깥의 그림은 Path의 형태로 따서 masking 하는 방법을 알아보았습니다.

해당 방법을 잘 활용해서 이쁜 UI를 짤 수 있으면 좋겠네요 :)

감사합니다 🙃

 

반응형