SwiftUI 리스트 만들기

이번에는 SwiftUI에서 리스트를 어떻게 만들고 다루는지 알아보겠습니다. 이 강좌는 Swift 기본 문법을 숙지하고 있다는 가정 하에 작성되었습니다.

리스트(List) 란

리스트는 이름 그대로 목록(List) 인터페이스를 구현하기 위해 존재합니다. SwiftUI의 리스트는 UIKit의 UITableView와 하는 일이 상당히 비슷합니다. 하지만 훨씬 간편합니다.

정적 리스트

정적 리스트에 대한 예시를 보여드리겠습니다.

우선 FamilyRow라는 struct가 있습니다. 이 struct는 name 변수와 Text를 리턴하는 body를 갖고 있습니다. List의 아이템으로 FamilyRow를 넣어주고, 각각의 FamilyRow에 서로 다른 name을 입력해줍니다.

그리고 실행해보면, 각 FamilyRow의 텍스트가 리스트 형태로 표시되는 것을 볼 수 있습니다.

struct FamilyRow: View {
    var name: String

    var body: some View {
        Text("Family: \(name)")
    }
}

struct ContentView: View {
    var body: some View {
        List {
            FamilyRow(name: "Hohyeon")
            FamilyRow(name: "Gomin")
            FamilyRow(name: "Durup")
        }
    }
}

다이나믹 리스트

Family라는 Identifiable 프로토콜을 상속 받는 struct가 있습니다. Identifiable을 상속 받기 위해서는 고유 id 값만 있으면 되는데요. Family struct에 id와 name 변수를 선언합니다.

FamilyRow는 정적 리스트를 다룰 때와 비슷한데요. 다이나믹 리스트를 구성하는 것인만큼 정적인 name 변수 대신 family라는 Family 타입 변수를 선언합니다.

ContentView에서는 리스트에 들어갈 first, second, third 아이템을 만들고 families 배열에 넣어준 뒤, return 값으로 리스트를 반환합니다. families 배열안에 있는 family element를 각각 반복 실행해서 리스트에 보여줍니다.

struct Family: Identifiable {
    var id = UUID()
    var name: String
}
struct FamilyRow: View {
    var family: Family
    var body: some View {
        Text("Family: \(family.name)")
    }
}
struct ContentView: View {
    var body: some View {
        let first = Family(name: "Hohyeon")
        let second = Family(name: "Gomin")
        let third = Family(name: "Durup")
        let families = [first, second, third]
        return List(families) { family in
            FamilyRow(family: family)
        }
    }
}

리스트 아이템 삭제

리스트의 아이템을 삭제하기 위해서는 어려울것 없습니다. ForEach로 뿌려진 Text 아이템 뒤에 .onDelete(perform: )을 달아줍니다. 그리고 삭제 버튼을 누르면 실행할 함수를 정의 해줍니다.

struct ContentView : View {
    @State var users = ["Hohyeon", "Gomin", "Durup"]

    var body: some View {
        List {
            ForEach(users, id: \.self) { user in
                Text(user)
            }
            .onDelete(perform: delete)
        }
    }
    
    func delete(at offsets: IndexSet) {
        if let first = offsets.first {
            users.remove(at: first)
        }
    }
}

리스트 아이템 편집

리스트의 아이템을 편집하기 위해서는 편집 버튼과 편집 상태에서 작동하는 함수의 정의가 필요한데요.

우선, 네비게이션 바 아이템으로 편집 버튼을 만들고, .onMove(perform: )으로 편집 상태에 진입 했을 때 작동할 함수를 부여합니다.

그리고 편집 상태에서 실행할 함수를 정의 해줍니다.

struct ContentView : View {
    @State var users = ["Hohyeon", "Gomin", "Durup"]

    var body: some View {
        NavigationView {
            List {
                ForEach(users, id: \.self) { user in
                    Text(user)
                }
                .onMove(perform: move)
            }
            .navigationBarItems(trailing: EditButton())
        }
    }

    func move(from source: IndexSet, to destination: Int) {
        let reversedSource = source.sorted()

        for index in reversedSource.reversed() {
            users.insert(users.remove(at: index), at: destination)
        }
    }
}

리스트에 섹션 추가

리스트에 섹션을 추가하기 위해서는 리스트안에 Section(header: ){}을 넣어주고, 그 안에 리스트 아이템을 넣어줍니다.

struct TaskRow: View {
    var body: some View {
        Text("Task item")
    }
}
struct ContentView : View {
    var body: some View {
        List {
            Section(header: Text("Important")) {
                TaskRow()
                TaskRow()
                TaskRow()
            }
            Section(header: Text("Other")) {
                TaskRow()
                TaskRow()
                TaskRow()
            }
        }
    }
}

리스트 그룹화

리스트를 그룹화하려면, 리스트에 섹션을 추가할 때와 똑같이 코드를 작성하고 List 뒤에 .listStyle(GroupedListStyle())를 달아줍니다.

struct GroupedRow: View {
    var body: some View {
        Text("Grouped Row")
    }
}

struct ContentView : View {
    var body: some View {
        List {
            Section(header: Text("Grouped")) {
                GroupedRow()
                GroupedRow()
                GroupedRow()
            }
        }.listStyle(GroupedListStyle())
    }
}

마무리

이렇게 해서 SwiftUI에서는 리스트를 어떻게 만드는지에 대해 알아봤는데요. 다음에는 SwiftUI에서 스크롤 뷰를 어떻게 만드는지 알아보겠습니다.

관련 글