관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - SwiftUI] 뷰를 주입 받는 형태의 커스텀 뷰 만드는 방법 (custom view에 View 주입하는 테크닉) 본문

iOS 응용 (SwiftUI)

[iOS - SwiftUI] 뷰를 주입 받는 형태의 커스텀 뷰 만드는 방법 (custom view에 View 주입하는 테크닉)

jake-kim 2024. 11. 26. 01:48

커스텀 뷰 만들기

  • 간단한 커스텀 뷰의 경우는 단순히 데이터만 받아서 그 데이터에 맞게끔 뷰가 그려지지만, 데이터와 특정 뷰를 주입하여 그 뷰도 커스텀 뷰의 하나가 되도록 설계도 가능
  • 뷰를 주입받는 형태로 구현해야하는데 좋은 방법은? 아래에서 계속

뷰를 주입받는 형태로 구현하는 테크닉

ex) 예제로 사용할 뷰: 상단에 header 타이틀 형태가 있고 하단에는 배열로 넣어준 뷰들이 보여지는 뷰

struct ContentView: View {
    var body: some View {
        CustomView(title: "상단 타이틀", items: [1,2,3]) { item in
            Text("item: \(item)")
        }
    }
}

커스텀 뷰

  • 1) 사용하는 쪽에서 만들 뷰에 필요한 데이터 배열을 넣어주는 파라미터 정의
    • 아래 코드에서 items 부분
CustomView(title: "상단 타이틀", items: [1,2,3]) { item in
    Text("item: \(item)")
}
  • CustomView에 제네릭스를 사용하여 T 배열로 받도록 선언
struct CustomView<T: Hashable>: View {
    let items: [T]
}
  • 2) 위에서 넣어준 데이터 배열들을 가지고 뷰를 그려주어야 하는데, 이 그려주는 부분을 사용하는쪽에서 정해주기 위해 클로저 배열로 선언
    • 위에서 넘겨준 데이터 하나를 가지고 어떻게 그릴지 정의해주는 구조
    • 이것도 제네릭스를 사용하여 V로 선언하고, 이 클로저를 전역변수에 저장
struct CustomView<T: Hashable, V: View>: View {
    let items: [T]
    let viewMapping: (T) -> V // <-
}
  • 3) 주입받은 데이터들과 클로저를 사용하여 나머지 구현
struct CustomView<T: Hashable, V: View>: View {
    let title: String
    let items: [T]
    let viewMapping: (T) -> V

    var body: some View {
        VStack {
            Text("-- \(title) --")
                .foregroundStyle(Color.blue)
            
            content()
        }
    }

    private func content() -> some View {
        ForEach(self.items, id: \.self) { item in
            viewMapping(item)
        }
    }
}

 

완료) 사용하는 쪽에서는 데이터와 클로저에 뷰의 구현부를 넘겨주면 완료

struct ContentView: View {
    var body: some View {
        CustomView(title: "상단 타이틀", items: [1,2,3]) { item in
            Text("item: \(item)")
        }
    }
}

 

* 전체 코드

struct ContentView: View {
    var body: some View {
        CustomView(title: "상단 타이틀", items: [1,2,3]) { item in
            Text("item: \(item)")
        }
    }
}

struct CustomView<T: Hashable, V: View>: View {
    let title: String
    let items: [T]
    let viewMapping: (T) -> V

    var body: some View {
        VStack {
            Text("-- \(title) --")
                .foregroundStyle(Color.blue)
            
            content()
        }
    }

    private func content() -> some View {
        ForEach(self.items, id: \.self) { item in
            viewMapping(item)
        }
    }
}

 

* 읽어보면 좋은 글: 설계 관점에서 클로저를 이해하며 잘 사용하기

Comments