
Mask
SwiftUI
에서는 mask()
수정자를 사용하여 이미지 또는 텍스트를 마스크 할 수 있습니다.
간단한 예제를 보면서 어떻게 사용할 수 있는지 알아보도록 할게요.
VStack { Image("sample2") .resizable() .aspectRatio(contentMode: .fit) .mask( ZStack { Circle() .frame(width: 208, height: 208) Circle() .frame(width: 90, height: 90) .offset(x: 80, y: 55) } ) .frame(maxHeight: .infinity) }

이제 mask
를 활용해서 평점을 줄 수 있는 버튼을 하나 만들어 줄까 해요.
우선 별이 5개인 뷰를 만들어줍니다.
import SwiftUI struct maskView: View { var body: some View { ZStack { starsView } } private var starsView: some View { HStack { ForEach(1..<6) { star in Image(systemName: "star.fill") .foregroundColor(.gray) } } } }
그리고 starsView
에 overlay
와 mask
를 사용하여 회색인 별을 노란색으로 채워주겠습니다.
ZStack { starsView .overlay( GeometryReader { geo in Rectangle() .fill(Color.yellow) .mask(starsView) } ) }
이제 frame
을 적용해서 숫자가 올라갈수록 rectangle
의 frame
넓이도 바뀔 수 있도록 구현해줘야 합니다.
@State
속성을 사용하여 rating
을 0으로 설정해줍니다.
struct maskView: View { @State var rating: Int = 1 var body: some View { ZStack { starsView .overlay( GeometryReader { geo in ZStack(alignment: .leading) { Rectangle() .foregroundColor(.yellow) .frame(width: CGFloat(rating) / 5 * geo.size.width) } } ) } }
@State
의 rating
값을 하나씩 올려보면 별의 색도 채워지는 것을 확인할 수 있습니다. 그리고 overlay
뷰를 생성하고 위에 있는 코드를 옮겨줍니다.
var body: some View { ZStack { starsView .overlay( overlayView ) } } private var overlayView: some View { GeometryReader { geo in ZStack(alignment: .leading) { Rectangle() .foregroundColor(.yellow) .frame(width: CGFloat(rating) / 5 * geo.size.width) } } }
overlayView
아래 mask
를 적용해볼게요.
.overlay( overlayView .mask(starsView) )

자, 그럼 starsView
로 돌아가서 버튼을 눌렀을 때마다 별이 채워질 수 있도록해줘야겠죠? foregroundColor
아래 onTapGesture
을 추가해줍니다.
private var starsView: some View { HStack { ForEach(1..<6) { star in Image(systemName: "star.fill") .foregroundColor(.gray) .onTapGesture { rating = star } } } }
withAnimation
을 사용하면 더 보기 좋아집니다.
.onTapGesture { withAnimation(.easeInOut(duration: 0.3)) { rating = star } }
그런데 한 가지 문제가 있습니다.
별 한 개 에서 -> 다섯 개로 높아질 때는 정상적으로 클릭이 가능한데, 5에서 4로 내리면 클릭이 되지를 않습니다.
이유는 우리는 지금 overlayView
를 클릭하고 있기 때문입니다.
onTapGesture
은 starsView
에 줬는데 말이죠. 이럴 때는 overlayView
에 .allowsHitTesting(false)
를 할당해주면 완벽히 해결됩니다.
private var overlayView: some View { GeometryReader { geo in ZStack(alignment: .leading) { Rectangle() .foregroundColor(.yellow) .frame(width: CGFloat(rating) / 5 * geo.size.width) } } .allowsHitTesting(false) }

이제 앱을 닫았을 때도 평점이 저장될 수 있도록 UserDefaults
를 한번 사용해볼게요.
starsView
의 onTapGestire
아래에 다음과 같이 userDefaults
를 추가합니다.
private var starsView: some View { HStack { ForEach(1..<6) { star in Image(systemName: "star.fill") .foregroundColor(.gray) .onTapGesture { withAnimation(.easeInOut(duration: 0.3)) { rating = star UserDefaults.standard.setValue(rating, forKey: "rating_key") } } } } }
그리고 @State
도 아래와 같이 수정합니다.
@State var rating: Int = UserDefaults.standard.integer(forKey: "rating_key")
자 이렇게 앱을 종료 후 재 시작을 해도 부여해줬던 평점이 그대로 저장된 것을 확인할 수 있습니다.
import SwiftUI struct maskView: View { @State var rating: Int = UserDefaults.standard.integer(forKey: "rating_key") var body: some View { ZStack { starsView.overlay(overlayView.mask(starsView)) } } private var overlayView: some View { GeometryReader { geo in ZStack(alignment: .leading) { Rectangle() .foregroundColor(.yellow) .frame(width: CGFloat(rating) / 5 * geo.size.width) } } .allowsHitTesting(false) } private var starsView: some View { HStack { ForEach(1..<6) { star in Image(systemName: "star.fill") .foregroundColor(.gray) .onTapGesture { withAnimation(.easeInOut(duration: 0.3)) { rating = star UserDefaults.standard.setValue(rating, forKey: "rating_key") } } } } } }
이미지도 추가해볼게요.
전체 코드

읽어주셔서 감사합니다🤟
본 게시글의 전체 코드 GitHub 👇🏻
Seogun95/SwiftUI_ContinuedLearning
SwiftUI 고급 기능 튜토리얼. Contribute to Seogun95/SwiftUI_ContinuedLearning development by creating an account on GitHub....
github.com
'SWIFTUI > Others' 카테고리의 다른 글
SwiftUI : Background Threads / Queues (0) | 2021.06.07 |
---|---|
SwiftUI : @FetchRequest 속성 래퍼 [Core Data #1] (1) | 2021.06.05 |
SwiftUI : Gesture (0) | 2021.05.29 |
SwiftUI : Markups과 Documentation을 추가하는 방법 (0) | 2021.05.13 |
SwiftUI : ActionSheet (0) | 2021.05.12 |