TableView, CollectionView 에서 Delegate 사용
iOS 13+ 부터 가능함!
TableView or CollectionView는 따로 만들었다는 가정하에 Delegate를 사용하는 법만 확인
UITableViewDelegate or UICollectionViewDelegate에 있는 contextMenuConfigurationForItemsAt
함수를 정의해 만들 수 있다.
예제는 CollectionView지만 TableView도 동일하게 사용이 가능함!
extension HomeViewController: UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemsAt indexPaths: [IndexPath], point: CGPoint) -> UIContextMenuConfiguration? {
// 현재 섹션이 어떤건지 확인 (1번 섹션은 Add 메뉴만 뜨고, 2번 섹션은 Delete 메뉴만 뜨게 하기 위해)
guard let indexPathSection = indexPaths.first?.section else { return nil }
let section = HomeSection.allCases[indexPathSection]
// iOS 13+ context menu configuration
return UIContextMenuConfiguration(identifier: nil, previewProvider: nil) { suggestedActions in
let addAction = UIAction(title: "즐겨찾기 추가", image: UIImage(systemName: "star")) { [weak self] action in
self?.viewModel.addIndexPath.send(indexPaths.first)
}
let deleteAction = UIAction(title: "즐겨찾기 제거", image: UIImage(systemName: "trash"), attributes: .destructive) { [weak self] action in
self?.viewModel.deleteIndexPath.send(indexPaths.first)
}
return UIMenu(
title: "",
children: section == .common ? [addAction] : [deleteAction]
)
}
}
}
UIContextMenuConfiguration
에 사용할 메뉴들을 정의해서 반환해주면 된다.
내가 사용한 방법은 하나만 꾹 선택하는 방식이지만, multiSelect하고 나오는 ContextMenu에 대한 처리는 IndexPath가 배열로 들어오기 때문에 이 예제와 비슷하게 해도 문제 없을 것 같다. (해봐야 알겠지만,,,)
UIContextMenuConfiguration 에는 3가지의 파라미터가 있다.
identifier
ContextMenu의 ID.
nil을 넣어주면 UUID 값을 자동으로 생성해줌previewProvider
꾹 눌렀을 때 highlight? 되는? preview를 넣어주면 된다. nil로 하면 그냥 선택된 셀을 preview로 보여준다.
만약 ViewController 를 주입해서 사용할 경우 커스텀도 가능하다.actionProvider
여기에 메뉴에 들어갈 액션을 만들어서 반환해주면 된다.
previewProvider를 사용하는법을 간략히 보고가자
...
return UIContextMenuConfiguration(identifier: nil, previewProvider: PreviewViewController(imageURL) { suggestedActions in
...
}
...
final class PreviewViewController: UIViewController {
private let imageThumbnail: String
private let imageView: UIImageView = {
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
imageView.contentMode = .scaleAspectFit
return imageView
}()
init(_ imageURL: String) {
self.imageThumbnail = thumbnailURL
super.init(nibName: nil, bundle: nil)
}
@available(*, unavailable)
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
setupView()
}
private func setupView() {
view = imageView
view.backgroundColor = .white
imageView.load(url: URL(string: imageThumbnail))
preferredContentSize = imageView.frame.size
}
}
임시로 아무 예제를 들고왔는데,
먼저 Preview로 사용할 ViewController를 생성해주고 파라미터에 넣어주면 된다.
Preview에 보여질 UI를 만들고 정의해주면 끝!!
Preview 크기의 경우 위 코드에서는 preferredContentSize = imageView.frame.size
를 사용해서 이미지 크기에 맞게 조절한걸 알 수 있다.
preferredContentSize
? - 크기를 조정할 수 있는 컨트롤러에서 많이 사용됨. 원하는 크기를 지정하는 속성 (UIPopoverPresentationController, UISheetPresentationController 등에서도 많이 사용됨)