Starbucks Caramel Frappuccino
본문 바로가기
  • 그래 그렇게 조금씩
SwiftUI/SwiftUI(Intermediate)

15. mask 마스킹

by Toughie 2023. 5. 26.

⭐️mask 마스킹⭐️

마스킹 테이프.. 피그마의 마스크와 같이 SwiftUI에서도 마스크 기능을 사용할 수 있다.

별점 등록 뷰를 만들어 보고 마스크 없이 했을 때와, 마스크를 썼을 때 할 수 있는 것과 차이점을 알아보자.

//  Created by Toughie on 2023/05/26.
//

import SwiftUI

struct starRating: View {
    
    @State var rating = 0
    
    var body: some View {
        HStack {
            ForEach(1..<6) { index in
                Image(systemName: "star.fill")
                    .font(.largeTitle)
                    .foregroundColor(rating >= index ? Color.yellow : Color.gray)
                    .onTapGesture {
                        withAnimation(.spring()) {
                            rating = index
                        }
                    }
            }
        }
    }
}

사실 시중 앱에서 별점을 매길 때 애니메이션이 없는 경우가 대부분 같아서.. 이정도 애니메션도 나쁘지 않아 보인다.

하지만 별이 앞에서부터 촤르륵 채워지는 효과를 구현하고 싶은 경우 mask를 활용할 수 있다.
(물론 애니메이션 구현에는 다양한 방법이 있겠지만.)

 

마스크를 사용하면 이런 그라데이션 효과도 줄 수 있다..ㅋㅋㅋ

//  Created by Toughie on 2023/05/26.
//

import SwiftUI

struct MaskPractice: View {
    @State var rating: Int = 0
    
    var body: some View {
        ZStack {
            starsView
            //별모양 위에 overlay를 통해 마스킹 테이프를 붙이는 느낌
                .overlay(
                    overlayView
                        .mask(starsView)
                )
        }
    }
    
    private var starsView: some View {
        HStack {
            ForEach(1..<6) { index in
                Image(systemName: "star.fill")
                    .font(.largeTitle)
                    .foregroundColor(.gray)
                	//별점 변경을 위한 탭제스쳐
                    .onTapGesture {
                    //다양한 애니메이션을 써봤지만 여기서는 거의 다 비슷한 느낌이었다.
                        withAnimation(.spring()) {
                            rating = index
                        }
                    }
            }
        }
    }
    
    //마스킹 테이프~
    private var overlayView: some View {
        GeometryReader { geo in
        //정렬을 위해 ZStack 사용(항상 앞부분부터 채워져야함)
            ZStack(alignment: .leading) {
                Rectangle()
                    .fill(LinearGradient(gradient: Gradient(colors: [Color.pink, Color.yellow, Color.green, Color.blue]), startPoint: .topLeading, endPoint: .bottomTrailing))
                    //필요한 부분만큼만 마스킹 하기 위해
                    .frame(width: CGFloat(rating) / 5 * geo.size.width)
            }
        }
        //마스크 부분은 터치하지 못하도록(별을 눌러서 index 변경을 해야함)
        //이 코드가 없으면 Rectangle에 가려져 뒤에 별을 탭하지 못함
        .allowsHitTesting(false)
    }
}