SwiftUI 리스트 컴포넌트

2023년 1월 3일 수정

리스트(List)

SwiftUI의 가장 기본적인 정적 리스트는 아래와 같은 방식이다.

List {
    SomeRowView()
    SomeRowView()
}

비슷하게 ForEach 를 활용할 수도 있다.

List {
    ForEach(items, id: \.self) { item in
        SomeRowView(item)
    }
}

데이터 모델을 사용한 동적 리스트는 아래와 같은 방식이다.

List(someItemList, id: \.id) { item in
    SomeRowView(item)
}

해당 데이터가 각 아이템 타입이 Identifiable 프로토콜을 따른다면 id 필드를 생략할 수도 있다.

리스트 스타일

listStyle 을 이용해 테이블 스타일을 지정할 수 있다.

List {
    ...
}.listStyle(GroupedListStyle())  // or PlainListStyle()

리스트 셀 삭제 구현

리스트 셀 삭제 구현 1 - 스와이프 방식

삭제 기능은 기본적으로 리스트 자체에서 제공한다. 기본 구현으로 각 셀을 스와이프(swipe)하는 방법으로 삭제할 수 있께 해준다.

하지만 실제 데이터를 가공하는 것은 개발자의 몫이다. 이 가공을 위해 데이터 소스에서 .onDelete(perform:) 메서드를 통해 호출되는 클로저를 사용할 수 있다. 대충 아래와 같은 형식이다.

List {
    ForEach(items, id: \.self) { item in
        SomeView(item)
        ...
    }.onDelete { indexSet in
        // 데이터소스 가공하기
        items.remove(atOffsets: indexSet)
    }
}

당연하게도 .onDelete(perform:) 에서 아무 일도 하지 않거나 혹은 클로저 대신 nil 을 넘겨주면 삭제가 되지 않는다.

리스트 셀 삭제 구현 2 - 편집 버튼 방식

스와이프가 아니라 삭제 버튼이 표시되는 방법을 원한다면 EditButton 을 툴바에 넣어주자.

List {
    ForEach(items, id: \.self) { item in
        SomeView(item)
        ...
    }.onDelete { indexSet in
        items.remove(atOffsets: indexSet)
    }
}
.toolbar {
    EditButton()  // <-- 이 녀석
}

역시 리스트에서 기본적으로 제공되는 삭제 방법으로 편집 버튼을 토글하면 각 셀의 좌측에 삭제 버튼이 표시되는 방식이다.

셀 삭제 비활성화

리스트의 각 셀에는 .deleteDisabled() 메서드를 통해 삭제 가능 여부를 지정해 줄 수 있다.

List {
    ForEach(items, id: \.self) { item in
        SomeView(item)
            .deleteDisabled(true)
        ...
    }.onDelete { indexSet in
        ...
    }
}

리스트 셀 이동 구현

리스트 셀 이동시키기

위의 삭제와 비슷하지만 셀 이동의 경우 클로저를 등록하는 메서드로 .onMove 를 쓸 수 있다.

List {
    ForEach(items, id: \.self) { item in
        SomeView(item)
        ...
    }.onMove { from, to in
        ...
    }
}
.toolbar {
    EditButton()  // <-- 이 녀석
}

위 코드는 툴바에 EditButton() 을 넣어서 셀 이동 인터페이스를 지원하고 있다. 이걸 안 쓴다면 셀을 길게 꾸욱 터치하는 식으로 이동시키는 것도 가능하다.

셀 이동 비활성화

일부 셀의 이동을 막으려면 각 셀에서 .moveDisabled() 메서드를 통해 비활성화 시키면 된다.

List {
    ForEach(items, id: \.self) { item in
        SomeView(item)
            .moveDisabled(item.enabled)
        ...
    }.onMove { from, to in
        ...
    }
}
...