SwiftUI | List (구. UITableView)

UITableView.
iOS의 기본 어플들에서도 빠지지않고 활용되고 있는 UI 컴포넌트이죠.


SwiftUI에서 UITableViewList 입니다.
UIImageViewImage가 된 것처럼 정말 직관적이고 생김새를 유추하기 쉬워졌죠? 🤭


이번 글에서는 List 의 사용방법에 대해 써보려합니다. 고고씽 ~~~~ !



List

기본 시계 App
카카오톡 설정화면
기본 설정 App
App store 검색화면

4개의 화면 모두 UIKitUITableView로 구현된 화면입니다.
SwiftUI 시대에서는 List 로 구현할 수 있는 화면들입니다.


List를 아직 많이 사용도 활용도 못해봐서 UITableView 대신에 List를 사용했을 때의 단점을 얘기하기는 이르지만,
장점은 ! 동적 데이터를 처리하기 아주아주 편리하다는 것입니다.

Binding 을 활용하면 지금까지의 tableView.reloadData() 등의 데이터 변경에 따른 갱신과 관련된 코드를 없앨 수 있습니다 😭

코드부터 보시죠.

struct ContentView: View {
    var body: some View {
        List {
            Text("1")
            Text("2")
            Text("3")
        }
    }
}

가득하던 UITableViewDelegate, UITableViewDataSource 도 없이 너무 간단하지않나요 😭



Custom Cell

struct CustomCell: View {
    var body: some View {
        HStack {
            Image(systemName: "tortoise.fill")
            Text("거북이")
        }
    }
}

struct CustomCell: View {
    var body: some View {
        List {
            CustomCell() 
            Text("1")
            Text("2")
            Text("3")
        }
    }
}

UITableView 에서 Custom Cell을 만들기 위해서는 UITableViewCell 을 만들어서,, 후아
아무튼 복잡했었죠

SwiftUI에서는 평범한 View 처럼 만들고 List 안에 쏙 넣어주면 Cell로 바로 기능을 한답니다. 👏👏

Section

struct ContentView: View {
    var body: some View {
        List {
            Section {
                CustomCell()
            }
            Section {
                Text("1")
                Text("2")
                Text("3")
            }
        }
    }
}

Section 의 구현자체는 간단한데 ListStyleDefault로 되어있으면 티가 나지 않네요… !
궁금하신 분들은 Group로 해보시면 바로 확인하실 수 있으실 거예욥



Section, Header & Footer

– List Style : Default

struct ContentView: View {
    var body: some View {
        List {
            Section(header: Text("First section")) {
                CustomCell()
            }
            Section(
                header: Text("Second section"),
                footer: FooterView()
            ) {
                Text("1")
                Text("2")
                Text("3")
            }
        }
    }
}

struct FooterView: View {
    var body: some View {
        VStack(alignment: .leading, spacing: 5.0) {
            Text("주의사항")
                .bold()
            Text("UIKit을 사용할 때 SwiftUI 생각이 자꾸만 나게됩니다.")
        }.padding(.top, 10.0)
    }
}

– List Style : List

struct ContentView: View {
    var body: some View {
        List {
            Section(header: Text("First section")) {
                CustomCell()
            }
            Section(
                header: Text("Second section"),
                footer: FooterView()
            ) {
                Text("1")
                Text("2")
                Text("3")
            }
        }.listStyle(GroupedListStyle())//💫
    }
}

– Custom Cell과 동일하게 View를 따로 만들어줘서 넣어주면 footer 로 바로 동작한답니다 ✨




Cell을 터치했을 때 다른 화면으로 이동하기

ListNavigationView의 하위 view로 선언되어있어야 해요 !

struct ContentView: View {
    var body: some View {
        NavigationView { // ✨
            List {
                CustomCell(cellNum: 2)
                CustomCell(cellNum: 3)
            }
            .listStyle(GroupedListStyle())
            .navigationBarTitle("List View")
        }
    }
}

struct CustomCell: View {
    var cellNum: Int

    var body: some View {
        HStack {
            // ✨ 반드시 ! NavigationLink 로 감싸줘야함.
            NavigationLink(destination: DetailView()) {
                Image(systemName: "tortoise.fill")
                Text("\(cellNum)")
            }
        }
    }
}

// Cell을 선택했을 때 이동될 View.
struct DetailView: View {
    var body: some View {
        Image("펭수")
    }
}

– Cell은 NavigationLink 으로 한 번 감싸줘야해요 !!!!!!!!!!
– 이동될 View도 다른 View와 동일하게 초기화 시켜서 넣어주면 끄읏 –




Array로 된 데이터를 List로 표시하기

⭐️⭐️⭐️⭐️⭐️
List에 표시될 Array의 내용물은
반드시 Identifiable 프로코콜을 따르는 class, struct 로 정의되어있어야 합니다.

struct Item: Identifiable {
    var id = UUID() // Int, String 등 hashble을 따르는 것들은 뭐든지 가능.
    let name: String
}

– List 내에서 식별될 수 있는 id 프로퍼티를 반드시 가지고 있어야합니다.


struct Item: Identifiable {
    var id = UUID() // Int, String 등 hashble을 따르는 것들은 뭐든지 가능.
    let name: String
}

struct ContentView: View {
    let items: [Item] = [Item(name: "Micheal"),
                        Item(name: "Tom"),
                        Item(name: "Belle")]

    var body: some View {
        NavigationView {
            List(items) { item in
                Text(item.name)
            }
            .listStyle(GroupedListStyle())
            .navigationBarTitle("List View")
        }
    }
}



List 의 항목 삭제, 수정

✔️List 의 항목 삭제와 수정을 위해서는 우선 items 가 상태 프로퍼티로 존재해야합니다.

1. 삭제

struct Item: Identifiable {
    var id = UUID() // 💫Int, String 등 hashble을 따르는 것들은 뭐든지 가능.
    let name: String
}

struct ContentView: View {
    // 💫 State property로 설정.
    @State private var items: [Item] = [Item(name: "Micheal"),
                        Item(name: "Tom"),
                        Item(name: "Belle")]

    var body: some View {
        NavigationView {
            List {
                // 💫 ForEach로 각각의 cell에 delete 메소드를 입력시켜주어야한다.
                ForEach(items) { item in
                    Text(item.name)
                }.onDelete(perform: didDeleteCell) // 💫
            }
            .listStyle(GroupedListStyle())
            .navigationBarTitle("List View")
        }
    }

    // 💫 parameter 에는 반드시 offsets 을 추가해야 함.
    func didDeleteCell(at offsets: IndexSet) {
        items.remove(atOffsets: offsets) // 💫 
        print("Deleted cell is \(offsets)")
    }
}

ForEach로 Array 에서 하나씩 item 을 만들어주고 onDelete 함수를 입력해주어야 합니다.
didDeleteCell 에서 따로 items remove를 해줘야하는건 SwiftUI 답지않은 부분이네요…… !😥

2. 수정

struct ContentView: View {
    @State private var items: [Item] = [Item(name: "Micheal"),
                        Item(name: "Tom"),
                        Item(name: "Belle")]

    var body: some View {
        NavigationView {
            List {
                ForEach(items) { item in
                    Text(item.name)
                }.onMove(perform: didMoveCell) // 💫
            }
            .listStyle(GroupedListStyle())
            .navigationBarTitle("List View")
            .navigationBarItems(trailing: EditButton()) // 💫
        }
    }

    // 💫 onMove에 들어갈 메소드는 parameter는 꼭 지켜주세용
    func didMoveCell(from sorce: IndexSet, to destination: Int) {}
}

– 수정할 때에는 onDelete 대신 onMove 를 넣어주시고 수정 버튼이 들어갈 navigationBarItem 을 추가해주시면 됩니당





정말 간단한 목록을 표시할 때는 SwiftUI를 활용한다면
UITableView보다 코드도 간단해지고 정말 좋을 것 같아요 !

얼른 SwiftUI가 일반화되는 시대가 왔으면 좋겠네요 😖
오늘도 즐거운 iOS 개발되세용


답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google photo

Google의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중