
How to use Mask in SwiftUI to create a 5-star rating button | Continued Learning #8

rating 변수 변화 감지 rating 값이 바뀔 때마다 마스크 뷰 너비 변경GeometryReader { geometry in
ZStack(alignment: .leading) {
Rectangle()
.fill(LinearGradient(gradient: Gradient(colors: [.red, .blue]), startPoint: .leading, endPoint: .trailing))
.frame(width: CGFloat(rating) / 5 * geometry.size.width)
}
}
.allowsHitTesting(false)
GeometryReader를 통해 별 뷰 전체의 너비를 알 수 있다. 별 뷰 전체의 너비를 통해 rating 값이 바뀔 때 현재 직사각형의 너비를 얼마나 줄지 결정할 수 있다.mask 모디파이어를 통해 마스킹하는 뷰 사이즈가 마스킹되는 뷰 사이즈로 바뀐다. 즉 '덮히는' 효과가 이루어진다.fill을 통해 색깔이, frame을 통해 직사각형 크기가 변경되고 있다. 실제로 rating 값에 따라 직사각형 크기가 변경될 뿐이지만, mask를 하고 있는 상태이기 때문에 별에 대한 색깔이 '차오르는' 것처럼 느껴질 것이다.rating을 감지하고 있는 starsView 위에 overlayView가 있기 때문에 overlayView가 starsView 크기만큼 커지게 되면 rating 감지가 되지 않는다. overlayView 자체가 터치 이벤트를 받지 못하도록 hitTesting을 사용한다.import SwiftUI
struct MaskBootCamp: View {
@State var rating: Int = 0
var body: some View {
ZStack {
starsView.overlay(overlayView.mask(starsView))
}
}
private var overlayView: some View {
GeometryReader { geometry in
ZStack(alignment: .leading) {
Rectangle()
.fill(LinearGradient(gradient: Gradient(colors: [.red, .blue]), startPoint: .leading, endPoint: .trailing))
.frame(width: CGFloat(rating) / 5 * geometry.size.width)
}
}
.allowsHitTesting(false)
}
private var starsView: some View {
HStack {
ForEach(1..<6) { index in
Image(systemName: "star.fill")
.font(.largeTitle)
.foregroundColor(.gray)
.onTapGesture {
withAnimation(.easeInOut) {
rating = index
}
}
}
}
}
}
