Skip to content

노래 track list를 만들어보자! (part1: SwiftUI를 이용하여 Cell 디자인하기)

강병민 (Byungmin Kang) edited this page Nov 24, 2020 · 2 revisions

View를 만들기에 앞서 먼저 Model을 만들었습니다

struct Track: Identifiable {
    let id: Int
    let title: String
    let artist: String
    var isFavorite: Bool
}

상대적으로 간단한 model입니다

이제 본격적으로 view를 만들어보겠습니다

struct HeartAccessoryView: View {
    var isFavorite: Bool
    let toggleFavorite: (() -> Void)?
    
    var body: some View {
        Button(action: {
            toggleFavorite?()
        }, label: {
            Image(systemName: isFavorite ? "heart.fill" : "heart")
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: 20, height: 20, alignment: .center)
                .accentColor(.red)

        })
        .buttonStyle(BorderlessButtonStyle())
    }
}

struct EllipsisAccessoryView: View {
    var body: some View {
        Button(action: {
            print("show menu")
            
        }, label: {
            Image(systemName: "ellipsis")
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: 20, height: 20, alignment: .center)
                .accentColor(.gray)

        })
        .buttonStyle(BorderlessButtonStyle())
    }
}

swiftui의 장점은 preivew인데

struct Accessory_Previews: PreviewProvider {

    static var previews: some View {

        Group {
            Heart(isFavorite: true, toggleFavorite: nil)
            Ellipsis()
        }
        .previewLayout(.sizeThatFits)
    }
}

이렇게 딱 필요한 만큼만 preview해서 볼수 있습니다

이제 본격적으로 Cell에 들어가보면

struct TrackCell: View {

    let id: Int
    let title: String
    let artist: String
    let isFavorite: Bool
    var didToggleFavorite: (() -> Void)?

    var body: some View {
        HStack {
            Image(systemName: "photo")
                .resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: 38, height: 38, alignment: .center)
                .padding()
            TrackInfoView(title: title, artist: artist)
            Spacer()
            HStack(spacing: 20) {
                HeartAccessoryView(isFavorite: isFavorite, toggleFavorite: didToggleFavorite)
                EllipsisAccessoryView()
            }
            .padding(18)
        }
        .onTapGesture(perform: {
            print("tapped \(title)")
        })
    }
    
}

Heart와 Ellipsis와 마찬가지로 노래 정보를 보여주는 view를 따로 TrackInfoView라는 View로 빼놨습니다.

이떄

struct TrackCell: View {
    let track: Track
}   

으로 안하고 따로 풀어쓴 이유는 View는 Model에데해서 알아야하면 안된다고 생각하기 때문입니다

View는 멍청하게!

그러면 track의 정보를 어떻게 view에게 넘겨줄 수 있을까요?

extension을 이용하면 더 간편하게 이용할수 있습니다.

extension TrackCell {
    init(track: Track, didToggleFavorite: (() -> Void)?) {
        title = track.title
        artist = track.artist
        isFavorite = track.isFavorite
        id = track.id
        self.didToggleFavorite = didToggleFavorite
    }
}

그리고 역시나

struct TrackCell_Previews: PreviewProvider {

    static var previews: some View {
        let testTrack1 = Track(id: 1, title: "휘파람", artist: "BLACKPINK", isFavorite: true)
        let testTrack2 = Track(id: 2, title: "마지막처럼", artist: "BLACKPINK", isFavorite: false)

        Group {
            TrackCell(track: testTrack1, didToggleFavorite: nil)
            TrackCell(track: testTrack2, didToggleFavorite: nil)
                .preferredColorScheme(.dark)

        }
        .previewLayout(.sizeThatFits)
    }
}

프리뷰를 이용하여 cell의 디자인을 쉽게 알수 있습니다.

SwiftUI의 장점은 프리뷰를 통해서 다크모드일때도 쉽게 볼 수 있다는 점 입니다.

참고 자료

https://matteomanferdini.com/wp-content/uploads/2020/11/Diagram-for-the-MVVM-pattern-in-iOS-apps.png

Clone this wiki locally