• Jan
  • Feb
  • Mar
  • Apr
  • May
  • Jun
  • Jul
  • Aug
  • Sep
  • Oct
  • Nov
  • Dec
  • Sun
  • Mon
  • Tue
  • Wed
  • Thu
  • Fri
  • Sat
  • 27
  • 28
  • 29
  • 30
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

SwiftUI - Splitting Views in different files

if(kakao)2020을 보고 도전 ( ◠‿◠ )

image

꼴랑 맨 위에 3줄 짰는데 벌써 길어진 코드수… 속성들 1개당 한 줄씩 차지하다보니 너무 지저분해졌다.
이걸 그냥 한 파일에 View 변수를 선언해서 쓸 수도 있지만, apple이 권장하는 방법으로 해보기로 했다.

image

요렇게 깔끔한 View를 위해서!

기존의 코드를 먼저 보자. ‼️ 표시를 해둔 부분을 중심으로!

struct ContentView: View {
    
  	// ‼️ 다른 파일로 분리할 뷰에서 사용하는 변수들
    @State private var progressValue = 25.0
    @State private var progressTotal = 100.0
    
    var body: some View {
        ZStack{
            Color(red: 235/255, green: 235/255, blue: 235/255)
            VStack{
                Rectangle()
                    .fill(Color.white)
                    .frame(width: UIScreen.main.bounds.width, height:211)
                Spacer()
            }
            VStack{ // ‼️ 다른 파일로 분리하고싶은 VStack
                Text("D-78")
                    .font(.system(size: 30))
                    .fontWeight(.semibold)
                    .frame(height:47)
                    .padding(.top, 28)
                Text("다음 회고: 20.11.16 월")
                    .font(.system(size: 12))
                    .fontWeight(.medium)
                    .foregroundColor(.gray)
                ProgressView(value: progressValue, total: progressTotal)
                    .padding([.leading, .trailing], 33)
                    .progressViewStyle(HoneyBeeProgressViewStyle(value: $progressValue, total: $progressTotal)) // ‼️ HoneyBeeProgressViewStyle을 사용했다
                Text("조금만 더 힘내요! 현재 25% 달성했어요.")
                    .font(.system(size: 13))
                Spacer()
            }
            
        }
    }
}

//‼️ HoneyBeeProgressViewStyle 구현부
struct HoneyBeeProgressViewStyle: ProgressViewStyle { 
    @Binding var value: Double
    @Binding var total: Double
    
    func makeBody(configuration: Configuration) -> some View {
        let offset = CGFloat(value) / 100
        return GeometryReader{ geometry in
            VStack(spacing:0){
                HStack{
                    Text("🐝")
                        .font(.system(size: 21))
                        .scaleEffect(x: -1, y: 1, anchor: .center)
                        .frame(width: CGFloat(geometry.size.width * offset + 15), height: 30, alignment: .bottomTrailing)
                    Spacer()
                    Text("🍯")
                        .font(.system(size: 23))
                        .frame(width: 24, height: 30, alignment: .bottomTrailing)
                }
                ProgressView(configuration)
                    .accentColor(.yellow)
            }
        }
        .frame(height: 40)
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

코드를 살펴봤으니 이제 다른 파일로 분리해보자!

파일 만들기

File - New

image

SwiftUI View를 만들어주면 된다. - HomeProgressView.swift

만든 뷰 파일에 우리가 빼야 할 부분들을 다 빼준다.
SwiftUI View 파일을 만들면 처음 프로젝트를 열었을 때 나오는 ContentView.swift 초기 형식이랑 똑같기 때문에,
View 부분은 body 내부에 넣어주면 되고,
변수나 그 외 다른것들도 ContentView.swift 에 있던 같은 위치에 넣어주면 된다.

import SwiftUI
struct HomeProgressView: View{
  	//변수
    @State private var progressValue = 25.0
    @State private var progressTotal = 100.0
    
    var body: some View {
      	//VStack
        VStack{
            Text("D-78")
                .font(.system(size: 30))
                .fontWeight(.semibold)
            Text("다음 회고: 20.11.16 월")
                .font(.system(size: 12))
                .fontWeight(.medium)
                .foregroundColor(.gray)
            ProgressView(value: progressValue, total: progressTotal)
                .padding([.leading, .trailing], 33)
                .progressViewStyle(HoneyBeeProgressViewStyle(value: $progressValue, total: $progressTotal))
            Text("조금만 더 힘내요! 현재 25% 달성했어요.")
                .font(.system(size: 13))
            Spacer()
        }
    }
}

//ProgressViewStyle
struct HoneyBeeProgressViewStyle: ProgressViewStyle {
    @Binding var value: Double
    @Binding var total: Double
    
    func makeBody(configuration: Configuration) -> some View {
        let offset = CGFloat(value) / 100
        return GeometryReader{ geometry in
            VStack(spacing:0){
                HStack{
                    Text("🐝")
                        .font(.system(size: 21))
                        .scaleEffect(x: -1, y: 1, anchor: .center)
                        .frame(width: CGFloat(geometry.size.width * offset + 15), height: 30, alignment: .bottomTrailing)
                    Spacer()
                    Text("🍯")
                        .font(.system(size: 23))
                        .frame(width: 24, height: 30, alignment: .bottomTrailing)
                }
                ProgressView(configuration)
                    .accentColor(.yellow)
            }
        }
        .frame(height: 40)
    }
}

//이건 나중에 지워도 됨
struct HomeProgressView_Previews: PreviewProvider {
    static var previews: some View {
        HomeProgressView()
    }
}

ContentView 파일에서 불러와서 사용하기

이제 뷰를 분리했으니 ContentView.swift 파일은 이런 상태가 된다.
(분리한 부분은 당연히 지워준 상태)

import SwiftUI

struct ContentView: View {
    
    var body: some View {
        ZStack{
            Color(red: 235/255, green: 235/255, blue: 235/255)
            VStack{
                Rectangle()
                    .fill(Color.white)
                    .frame(width: UIScreen.main.bounds.width, height:211)
                Spacer()
            }
          	//원래 뷰가 있던 부분
          	HomeProgressView //이렇게 하면 되겠지?
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

난 카카오 스샷만 보고.. 원래 뷰가 있던 부분에 HomeProgressView만 써주면 될 줄 알았다.
근데 그럼 ZStack쪽에서 이런 오류가 난다.

image

Type ‘HomeProgressView.Type’ cannot conform to ‘View’; only struct/enum/class types can conform to protocols

HomeProgressView 이렇게만 쓰면, HomeProgressView 타입을 사용하는 것,,,
나는 지금 타입이 아니라 View를 써야하는 거니까,
object를 초기화해서 View를 사용하면 된다. : HomeProgressView()

struct ContentView: View {
    var body: some View {
        ZStack{
            Color(red: 235/255, green: 235/255, blue: 235/255)
            VStack{
                Rectangle()
                    .fill(Color.white)
                    .frame(width: UIScreen.main.bounds.width, height:211)
                Spacer()
            }
            HomeProgressView() //이렇게
        }
    }
}

엄청엄청 깔끔해진 모습! 위의 Rectangle()도 다 만들고 나면 분리할 예정이다.

image

잘 나온다 ( ◠‿◠ )

더 알아보고 싶은 것

  • fileprivate struct HomeProgressView: View {} 연결하는 법