SwiftUI 리스트와 내비게이션

2 분 소요

List 뷰 :

  • 수직 방향의 목록 형태로 사용자에게 정보를 제공하는 방법을 제공
  • 리스트 항목은 사용자가 터치했을 때 앱의 다른 영역으로 이동 ( 내비게이션 )
  • 정적 데이터와 동적 데이터 모두를 표현가능
  • 추가, 삭제, 항목 순서 재정렬 작업가능

SwiftUI 리스트

UIKit의 TableView 클래스와 비슷한 기능

struct ContentView: View {
    var body: some View {
        Text("Wash the car")
        Text("Vacuum house")
        Text("Pick up kids from school bus @ 3pm")
        Text("Auction the kids on eBay")
        Text("Order Pizza for dinner")
    }
}

스크린샷 2022-06-02 오전 10 21 11

여러 컴포넌트를 조합해서 셀에 표시

List {
    HStack {
        Image(systemName: "trash.circle.fill")
        Text("Take out the trash")
    }
    HStack {
        Image(systemName: "person.2.fill")
        Text("Pick up the kids")
    }
    HStack {
        Image(systemName: "car.fill")
        Text("Wash the car")
    }
}

스크린샷 2022-06-02 오전 10 23 44


SwiftUI 동적 리스트

동적: 변할 수 있는 항목들(추가, 편집, 삭제)
표시될 데이터는 Identifiable 프로토콜 을 따르는 클래스 또는 구조체 내에 포함
-> Identifiable 프로토콜을 사용하려면, id 프로퍼티 가 객체에 존재
(리스트에서 각 항목을 고유하게 식별하는데 사용)

  • 표준 스위프트 타입
  • Hashable 프로토콜을 따르는 모든 스위프트 타입(String, Int, UUID..)
  • 커스텀 타입
struct ToDoItem : Identifiable {
    var id = UUID()
    var task: String
    var imageName: String
}

배열을 이용한 리스트 데이터 제공

var listData: [ToDoItem] = [
    ToDoItem(task: "Take out trash", imageName: "trash.circle.fill"),
    ToDoItem(task: "Pick up the kids", imageName: "person.2.fill"),
    ToDoItem(task: "Wash the car", imageName: "car.fill")

]

struct ContentView: View {
    var body: some View {
    
        List(listData) { item in
            HStack {
                Image(systemName: item.imageName)
                Text(item.task)
            }
        }
    }
}

반복문을 실행하여 HStack 선언부를 재사용

동적 데이터와 정적 데이터를 함께 표현하는 경우: ForEach 구문 사용

struct ContentView: View {

    @State var toggleStatus = true
    
    var body: some View {
    
        List {
        
            Toggle(isOn: $toggleStatus) { // 정적 데이터
                Text("Allow Notifications")
            }
            
            ForEach (listData) { item in // 동적 데이터
                HStack {
                    Image(systemName: item.imageName)
                    Text(item.task)
                }
            }
        }
    }
}

스크린샷 2022-06-02 오전 10 44 35

Section 구현

List {
    Section(header: Text("Settings")) {
        Toggle(isOn: $toggleStatus) {
            Text("Allow Notifications")
        }
    }
            
    Section(header: Text("To Do Tasks")) {
        ForEach (listData) { item in
            HStack {
                Image(systemName: item.imageName)
                Text(item.task)
            }
        }
    }
}

스크린샷 2022-06-02 오전 10 48 54


NavigationView와 NavigationLink

리스트의 항목을 터치하여 다른 화면으로 이동

  1. 리스트를 NavigationView 안에 넣는다.
  2. 리스트의 각 행을 NavigaionLink 컨트롤로 감싼다.
var body: some View {
    NavigationView {
        List {
            Section(header: Text("Settings")) {
                Toggle(isOn: $toggleStatus) {
                    Text("Allow Notifications")
                }
            }
        
            Section(header: Text("To Do Tasks")) {
                ForEach (listData) { item in
                    HStack {
                        NavigationLink(destination: Text(item.task)) {
                            Image(systemName: item.imageName)
                            Text(item.task)
                        }
                    }
                }
            }
        }
    }
}

Navigaiton 타이틀 바 설정, 버튼 추가

NavigationView {
    List {
.
.
    }
    .navigationBarTitle(Text("To Do List"))
    .navigationBarItems(trailing: Button(action: addTask) {
        Text("Add")
    })
}

스크린샷 2022-06-02 오후 1 01 12 스크린샷 2022-06-02 오전 11 54 44


편집 가능하게 만들기

  • onDelete() 수정자: 데이터 소스에서 해당 항목을 삭제
      ForEach (listData) { item in
          HStack {
                  NavigationLink(destination: Text(item.task)) {
                  Image(systemName: item.imageName)
                  Text(item.task)
              }
          }
      }
      .onDelete(perform: deleteItem)
    

    func deleteItem(:IndexSet)

  • 각 셀이 삭제될 때 호출되는 함수
  • 삭제될 셀의 오프셋(offset)을 가진 IndexSet 객체 가 전달
  • 반드시 IndexSet을 매개변수로 받는다
    func deleteItem(at offsets: IndexSet) {
      // 데이터 소스에서 항목을 삭제하는 코드
    }
    

    스크린샷 2022-06-02 오후 12 35 42

  • onMove() 수정자: 데이터 소스에서 항목의 순서를 변경
    • 이동할 행의 현재 위치를 담고 있는 IndexSet 객체 와 이동하게 될 곳을 가리키는 정수 가 전달
  • EditButton 인스턴스: 버튼을 터치하면 자동으로 편집가능한 상태로 전환
      List {
      .
      .
         ForEach (listData) { item in
              HStack {
                  NavigationLink(destination: Text(item.task)) {
                  Image(systemName: item.imageName)
                  Text(item.task)
                  }
              }
          }
          .onDelete(perform: deleteItem)
          .onMove(perform: moveItem)
      .
      .
      }
      .navigationBarTitle(Text("To Do List"))
      .navigationBarItems(trailing: Button(action: addTask) {
          Text("Add")
      })
      .navigationBarItems(trailing: EditButton())
    
      func moveItem(from source: IndexSet, to destination: Int) {
          // 항목을 재배열하는 코드
      }
    

    스크린샷 2022-06-02 오후 12 36 52

카테고리:

업데이트: