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
}
}
}
}
}
}