SwiftUI

SwiftUI에서 shadow와 blur 사용하기

GREEN.1229 2024. 1. 8. 19:30

안녕하세요. 그린입니다 🍏

이번 포스팅에서는 자주 사용하고 있었는데 한번도 글로 정리해보지 않았던 shadow와 blur 모디파이어에 대해 정리해보겠습니다 🙋🏻

 

주의 ⚠️ 내용 다소 짧음!

 

공식문서들을 기반으로 알아볼거에요!
그럼 shadow부터 가시죠 🚀


shadow

SwiftUI에서 shadow 모디파이어는 뷰에 그림자를 추가해줍니다.

조금 더 뷰가 입체적으로 보일 수 있기에 저는 다른 뷰들과 조금 영역을 구분되어 보여줄때 자주 사용합니다!

SwiftUI를 적용할 수 있는 iOS 13.0 이상 버전이라면 사용 가능합니다.

 

func shadow(
    color: Color = Color(.sRGBLinear, white: 0, opacity: 0.33),
    radius: CGFloat,
    x: CGFloat = 0,
    y: CGFloat = 0
) -> some View

 

정의도 아주 심플해요.

 

여기서 color는 생성되는 그림자의 색상입니다.

원하는 그림자의 색상을 커스터마이징하여 넣을 수도 있고, 이미 Color의 정의된 static 상수를 통해 넣어줄 수도 있죠.

 

radius는 그림자를 얼마나 흐리게 나타낼지 정의하는 값입니다.

이 값이 클 수록 그림자는 더욱 흐릿하게 표현됩니다.

그림자 자체가 더욱 부드럽게 보여질 수 있죠.

즉 반대로, 값이 작을수록 그림자가 선명하게 보인다는 뜻이겠죠!

0이면 아예 흐려보이지 않게 뚜렷하게 그림자가 보입니다.

 

x는 해당 shadow를 적용하는 뷰에서 수평으로 그림자의 오프셋 위치를 이동시키는 값입니다.

예를들어, x가 10이면 해당 뷰에서 우측으로 10만큼 이동한 영역에서 그림자가 보이게 되고 반대로 음수로 나타내게 되면 뷰에서 좌측으로 그림자가 나타나게 됩니다.

 

y는 해당 shadow를 적용하는 뷰에서 수직으로 그림자의 오프셋 위치를 이동시키는 값입니다.

이것도 예를들어보면, y가 10이면 해당 뷰에서 수직인 아래 방향으로 10만큼 이동한 영역에서 그림자가 보이게 되고 반대로 음수로 나타나게 되면 뷰에서 상단인 위 방향으로 그림자가 나타나게 됩니다.

 

이 네가지 파라미터를 이용해 그림자를 그려주고 적용된 뷰를 반환해주게 됩니다.

 

그럼 shadow를 직접 공식문서처럼 코드로 구현하고 봐볼까요?

 

import SwiftUI

struct ContentView: View {
  let steps = [0, 10, 20]
  
  var body: some View {
    VStack(spacing: 50) {
      ForEach(steps, id: \.self) { offset in
        HStack(spacing: 50) {
          ForEach(steps, id: \.self) { radius in
            Color.green
              .shadow(
                color: .blue,
                radius: CGFloat(radius),
                x: CGFloat(offset), y: CGFloat(offset))
              .overlay {
                VStack {
                  Text("\(radius)")
                  Text("(\(offset), \(offset))")
                }
              }
          }
        }
      }
    }
    .padding(.horizontal, 20)
  }
}

 

해당 코드를 예시로 보겠습니다.

행과 열을 가진 이차원 구조속에서 각 그림자의 정도와 x,y 오프셋을 다르게 가질때 뷰를 적용합니다.

 

먼저 shadow 즉, 그림자의 컬러는 블루로 줍니다.

radius는 0, 10, 20의 값을 가지기에 0이면 흐려보이는것없이 선명하게 표현되고 20으로 값이 커질 수록 흐려보이게 되죠.

x,y 값도 그림자의 오프셋을 나타나게 되니 20으로 갈 수록 현재 뷰에서 해당 오프셋만큼 x,y 오프셋이 벗어나 보이게 됩니다.

 

그럼 결과물을 볼까요?

 

 

오버레이로 올려진 텍스트의 위 텍스트가 현재 그림자의 정도인 radius를 뜻하며 아래 텍스트는 (x,y) 오프셋을 뜻합니다.

그렇기에 radius가 0이면 그림자가 흐림 효과 없이 선명하게 보여지죠.

반대로 20으로 갈수록 그림자가 부드럽게 흐려져서 보이게 됩니다.

x,y 좌표에 위치에 따라 그림자가 나타나는 즉, 시작되는 지점이 달라보이죠!

 

현재 그림자의 컬러는 blue로 주었지만, 이 값을 주지 않을 수도 있습니다.

해당 color를 지정하지 않으면 실제로 gray색상 처럼 보여지게 됩니다.

왜냐하면 파라미터의 기본 값이 해당 색상처럼 주어져있기 때문입니다.

 

 

마찬가지로, x,y 오프셋의 값도 지정하지 않을 수는 있지만 그렇다면 실제로는 그림자가 적용되었는지 전혀 모르게 나타나지 않습니다.

실제 파라미터의 기본값이 0으로 잡혀있기 때문이죠!

 

다만 radius의 값은 파라미터 기본값이 없기에 무조건 필수로 지정해줘야 합니다.

 

자 이렇게 shadow에 대해 알아봤습니다 🙋🏻

 

이번엔 shadow하면 연관되어 생각나는 blur에 대해 알아보겠습니다 😃


blur

SwiftUI에서 blur 모디파이어는 뷰에 가우시안 블러를 적용합니다.

 

여기서 가우시안 블러(Gaussian Blur)는 이미지를 처리할때 많이 사용되는 흐림 효과 중 하나입니다.

가우스 함수를 기반으로 이미지 상 각 픽셀에 대해 주변 픽셀의 값을 가중 평균하여 적용하는 방법입니다.

이 과정에서 중심 픽셀에 더 큰 가중치를 두고 거리가 멀수록 가중치를 줄여서 흐림 효과를 생성해내는것이죠.

 

즉, blur 처리를 통해 이미지의 노이즈를 감소시킬 수 있고, 이미지의 주요 부분을 강조하거거나 조금 부드럽게 처리하는 등 다양한 활용 목적을 가질 수 있습니다.

 

blur의 정의를 볼까요?

 

func blur(
    radius: CGFloat,
    opaque: Bool = false
) -> some View

 

shadow보다 더 단순한것 같죠?

 

radius는 블러의 흐름 정도를 뜻합니다.

이 값은 커질 수록 블러가 더 많이 입혀지게 되는것이죠.

실제로 텍스트의 경우 20의 수치를 넘어가니 사실 블러가 입혀졌는지 모를 정도로 블러 처리되어 아예 뷰가 보이지 않게 다가옵니다.

(이미지나, 컬러에 적용할때나 각 컴포넌트들 마다 실제 보이지지 않을 정도의 radius 수치는 다릅니다~)

반대로, 0의 수치를 가지게 되면 마찬가지로 블러 처리가 되었는지 모를 정도로 선명하게 보이죠!

 

opaque는 투명도를 허용하는지 여부를 나타내는 값입니다.

기본적으로 해당 값은 false를 갖지만, 만약 불투명한 흐림 효과를 지정하고 싶다면 true로 설정할 수 있습니다.

 

opaque는 흐림 효과를 렌더링하는 방식에 영향을 줄 수 있습니다.

즉, 뷰가 만약에 완전히 불투명하다고 표시되면 시스템은 뷰의 배경을 렌더링할 필요가 없다고 판단하여 작업하지 않기에 복잡한 뷰 계층에서는 렌더링 성능을 향상시킬 수 있죠.

 

그런데 실제 보통의 상황에서 opaque를 true로 두게되면 블러의 흐림 처리를 전혀 느끼지 못합니다.

그렇기에 개발단에서는 blur 사용 시 opaque를 컨트롤하기보다 radius 값을 통해 흐림 정도를 조절하는것이 더 적절한 구현이 될것 같아요.

 

opaque를 조정하는 경우는 내부적인 렌더링 최적화와 관련된 상황에서 조절하는것이 나아보입니다.

(크게 조절할 일이 어떨때인지는 아직 감이 없습니다 🥲)

 

그럼 예시 코드와 나타나는 형태로 알아볼까요?

 

import SwiftUI

struct ContentView: View {
  var body: some View {
    VStack {
      Text("Green is Green")
        .blur(radius: 3, opaque: true)
      
      Text("Green is Green")
        .blur(radius: 3)
      
      Color.green
        .frame(width: 50, height: 50)
        .blur(radius: 3)
    }
  }
}

 

이렇게 텍스트 두개와 그린 컬러 뷰 하나를 배치했습니다.

텍스트에선  blur의 radius는 같지만, opaque를 달리 적용해봤어요.

 

한번 어떻게 나타나는지 볼까요?

 

 

opaque를 true로 두게 되면 이렇게 불투명하게 마스킹처럼 가져져서 처리가 됩니다.

반면 radius만 조정한 텍스트는 이렇게 투명하게 블러 처리가 되죠.

마찬가지로 컬러 뷰 자체에도 적용이 가능하죠.

SwiftUI에서 뷰라면 모두 적용이 가능합니다!

 


정리

쉽게 결국 shadow는 그림자를 넣을때 사용하고 blur는 뷰를 흐리게 만들때 사용하죠.

이 두가지를 동시에 사용해도 되구요!

적절히 구성함으로써 뷰를 조금 더 원하는 효과를 가진 뷰로 탈바꿈하여 사용할 수 있습니다 😃

 


레퍼런스

 

shadow(color:radius:x:y:) | Apple Developer Documentation

Adds a shadow to this view.

developer.apple.com

 

blur(radius:opaque:) | Apple Developer Documentation

Applies a Gaussian blur to this view.

developer.apple.com