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

ProgressBar 진행바 만들기 / GeometryReader/ available size

by Toughie 2023. 5. 9.

앱 안내 온보딩 페이지 등에서 자주 보이는 진행바를 만들어 봤다.

여기서는 shape의 너비를 변경시키는 방식이다.

애니메이션을 적용해서 부드럽게 채워진다.

 

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

import SwiftUI

struct ProgressBarView: View {
    //탭뷰를 위한 상태 프로퍼티. tag에 따라 변경됨.
    @State private var selectedTab: Int = 0
    //selectedTab 변경에 따라 값이 바뀜 -> 진행바 너비 늘어남
    @State private var progress: CGFloat = 0
    
    let stringArray: [String] = ["안녕하세요!", "반가워요~", "준비", "시작!"]

    var body: some View {
        VStack {
            Spacer()
            
            ProgressBar(progress: $progress)
                
            Spacer()
            
            TabView(selection: $selectedTab) {
                ForEach(icons.indices, id: \.self) { index in
                    ZStack {
                        Rectangle()
                            .foregroundColor(.gray.opacity(0.8))
                        Text(icons[index])
                            .font(.largeTitle)
                            .foregroundColor(.white)
                    }
                }
            }
            .frame(height: UIScreen.main.bounds.height * 0.7)
            //원형 인디케이터 스타일
            .tabViewStyle(PageTabViewStyle(indexDisplayMode: .automatic))
            //뷰가 등장하면서 첫 칸이 채워지도록 하기 위한 코드.
            //없으면 진행바가 전혀 채워지지 않았다가, 탭을 넘기면 확 많이 채워짐(2개분)
            .onAppear {
                progress = CGFloat(selectedTab + 1) / CGFloat(icons.count)
            }
            //스와이프를 통해 selectedTab값이 변경되면
            //해당 값을 통해 progress 값을 업데이트해줌 
            .onChange(of: selectedTab) { newValue in
                withAnimation(.easeInOut(duration: 0.5)) {
                    progress = CGFloat(newValue + 1) / CGFloat(icons.count)
                }
            }
            Spacer()
        }
        .padding(.horizontal)
        .background(Color.black)
    }
}

프로그레스바

struct ProgressBar: View {
    @Binding var progress: CGFloat
    
    var body: some View {
        GeometryReader { geometry in
            ZStack(alignment: .leading) {
                RoundedRectangle(cornerRadius: 5)
                    .foregroundColor(.gray.opacity(0.3))
                RoundedRectangle(cornerRadius: 5)
                    .frame(width: geometry.size.width * progress)
                    .foregroundColor(.green)
            }
        }
        .frame(height: 10)
    }
}

여기서 간단하게 GeometryReader와 ZStack 동작 방식에 대해 알아보자.

GeometryReader는 부모 뷰의 크기를 읽고 자식 뷰에게 전달하는 뷰이다.

 

여기서는 탭뷰가 존재하는 ProgressBarView의 바디 부분의 VStack의 사이즈가 부모 뷰인 것이다.

이 사이즈에 맞게(*available size) RoundedRectangle의 너비가 정해지는 것이다.

 

* available size -> 부모 뷰가 자식 뷰에게 제공하는 공간의 크기

첫번째 RoundedRectangle의 너비는 available 사이즈에 따라 결정됨. (여기서는 부모뷰의 VStack의 사이즈)

 

'SwiftUI > SwiftUI(examples)' 카테고리의 다른 글

모델? 뷰모델?  (0) 2023.05.13
Data Essentials in SwiftUI #WWDC20  (0) 2023.05.10