[swift] Swift IGListKit에서 컬렉션 뷰 다중 선택 기능 구현하기

IGListKit은 iOS 앱 개발을 쉽게 할 수 있게 도와주는 라이브러리입니다. 이 라이브러리를 사용하면 컬렉션 뷰를 간편하게 구현할 수 있습니다. 이번 글에서는 IGListKit을 사용하여 컬렉션 뷰에서 다중 선택 기능을 구현하는 방법에 대해 알아보겠습니다.

IGListKit 설치 및 설정

우선 IGListKit을 프로젝트에 설치해야 합니다. Cocoapods를 사용한다면 Podfile에 다음과 같이 추가합니다:

pod 'IGListKit'

설치 후, 프로젝트를 열고 IGListKit을 import 합니다:

import IGListKit

다중 선택을 위한 모델 클래스 구현하기

먼저, 다중 선택을 위한 모델 클래스를 구현해야 합니다. 이 클래스는 선택 가능한 항목을 나타내며, 다음과 같은 속성을 가져야 합니다:

class SelectableItem {
    var name: String
    var isSelected: Bool
    
    init(name: String, isSelected: Bool = false) {
        self.name = name
        self.isSelected = isSelected
    }
}

이 클래스에는 항목 이름과 선택 여부를 나타내는 isSelected 속성이 있습니다. isSelected는 기본적으로 false로 초기화되며 선택되면 true로 변경됩니다.

컬렉션 뷰 데이터 소스 및 델리게이트 구현하기

다음으로, IGListKit의 ListAdapter를 사용하여 컬렉션 뷰의 데이터 소스와 델리게이트를 구현해야 합니다. ListAdapter에서는 다중 선택을 처리하기 위한 몇 가지 메서드를 구현해야 합니다.

class MultiSelectionViewController: UIViewController, ListAdapterDataSource, ListAdapterDelegate {
    let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
    let listAdapter = ListAdapter(updater: ListAdapterUpdater(), viewController: nil)
    var data: [SelectableItem] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 컬렉션 뷰 설정
        collectionView.collectionViewLayout = UICollectionViewFlowLayout()
        view.addSubview(collectionView)
        
        // ListAdapter 설정
        listAdapter.collectionView = collectionView
        listAdapter.dataSource = self
        listAdapter.delegate = self
        
        // 데이터 초기화
        data = [SelectableItem(name: "Item 1"), SelectableItem(name: "Item 2"), SelectableItem(name: "Item 3")]
        listAdapter.performUpdates(animated: true)
    }
    
    // MARK: - ListAdapterDataSource
    
    func objects(for listAdapter: ListAdapter) -> [ListDiffable] {
        return data
    }
    
    func listAdapter(_ listAdapter: ListAdapter, sectionControllerFor object: Any) -> ListSectionController {
        let sectionController = MultiSelectionSectionController()
        sectionController.selectionDelegate = self
        return sectionController
    }
    
    func emptyView(for listAdapter: ListAdapter) -> UIView? {
        return nil
    }
    
    // MARK: - ListAdapterDelegate
   
    func listAdapter(_ listAdapter: ListAdapter, didEndDisplaying sectionController: ListSectionController) {
        if let multiSelectionSectionController = sectionController as? MultiSelectionSectionController {
            multiSelectionSectionController.resetSelection()
        }
    }
}

위의 코드에서는 collectionView와 listAdapter를 초기화합니다. 데이터를 초기화하고 ListAdapter의 dataSource와 delegate를 설정합니다. objects(for:) 메서드에서는 데이터를 반환하고, listAdapter(_:sectionControllerFor:) 메서드에서는 ListSectionController를 설정합니다. emptyView(for:) 메서드는 컬렉션 뷰가 비어있을 때 표시할 뷰를 반환합니다.

ListSectionController 구현하기

다중 선택을 처리하기 위해 ListSectionController도 구현해야 합니다. ListSectionController는 IGListKit에서 컬렉션 뷰의 섹션을 관리하는 역할을 합니다. ListSectionController를 다음과 같이 구현합니다:

class MultiSelectionSectionController: ListSectionController {
    weak var selectionDelegate: MultiSelectionDelegate?
    var item: SelectableItem!
    
    override func size(for object: Any, at index: Int) -> CGSize {
        guard let context = collectionContext, let object = object as? SelectableItem else {
            return .zero
        }
        return CGSize(width: context.containerSize.width, height: 50)
    }
    
    override func cellForItem(at index: Int) -> UICollectionViewCell {
        let cell = collectionContext!.dequeueReusableCell(of: MultiSelectionCell.self, for: self, at: index) as! MultiSelectionCell
        cell.configure(with: item)
        return cell
    }
    
    override func didUpdate(to object: Any) {
        item = object as? SelectableItem
    }
    
    override func didSelectItem(at index: Int) {
        item.isSelected = !item.isSelected
        selectionDelegate?.didSelectItem(item)
        collectionContext?.performBatch(animated: true, updates: { context in
            context.reload(self)
        }, completion: nil)
    }
    
    func resetSelection() {
        item.isSelected = false
        collectionContext?.performBatch(animated: true, updates: { context in
            context.reload(self)
        }, completion: nil)
    }
}

위의 코드에서는 size(for:at:) 메서드에서 셀의 크기를 반환하고, cellForItem(at:) 메서드에서 셀을 설정합니다. didUpdate(to:) 메서드에서는 섹션 컨트롤러에 할당된 데이터를 업데이트하고, didSelectItem(at:) 메서드에서는 항목이 선택되었을 때 처리합니다. resetSelection() 메서드는 선택 상태를 초기화합니다.

MultiSelectionDelegate 프로토콜 구현하기

마지막으로, 다중 선택 이벤트를 처리하기 위해 MultiSelectionDelegate 프로토콜을 구현합니다:

protocol MultiSelectionDelegate: class {
    func didSelectItem(_ item: SelectableItem)
}

위의 코드는 didSelectItem(_:) 메서드를 포함한 프로토콜을 정의합니다. 이 메서드는 항목이 선택되었을 때 호출되며, 선택 상태를 처리할 수 있습니다.

마무리

위에서 설명한 방법을 참고하여 IGListKit을 사용하여 컬렉션 뷰에서 다중 선택 기능을 구현할 수 있습니다. IGListKit은 많은 기능을 제공하며, 다양한 앱에 적용할 수 있습니다. IGListKit의 공식 문서(참조: IGListKit 공식 문서)를 참고하면 더 많은 자세한 정보를 얻을 수 있습니다.