호댕의 iOS 개발

[iOS] TableView에서 Swipe를 통한 동작 구현하기 본문

Software Engineering/iOS

[iOS] TableView에서 Swipe를 통한 동작 구현하기

호르댕댕댕 2022. 3. 13. 18:18

연락처 앱이나 메모 앱을 켜보면 스와이프 기능이 있는 경우가 있다. 

스와이프를 통해 해당 셀을 삭제하거나 공유할 수 있도록 하는 것이다.

 

이는 굳이 버튼을 누르지 않더라도 직관적으로 스와이프 동작을 통해 원하는 액션을 동작할 수 있도록 할 수 있다. 

그렇다면 이런 스와이프 기능을 구현하려면 어떻게 해야할까?

 

 

🛠 관련 메서드

이는 UITableViewDelegate에 관련된 메서드를 사용하면 된다. 

  • func tableView(_ tableView:leadingSwipeActionsConfigurationForRowAt:) -> UISwipeActionsConfiguration?
  • func tableView(_ tableView:trailingSwipeActionsConfigurationForRowAt:) -> UISwipeActionsConfiguration?

 

이 메서드들은 각각 leading으로 swipe를 했을 때, trailing으로 swipe를 했을 때 각각의 동작을 구현할 수 있는 것이다. 

 

즉, tableView(_ tableView:leadingSwipeActionsConfigurationForRowAt:) 메서드의 경우 한국처럼 왼쪽에서 글을 읽는 문화권이라면 왼쪽에서 오른쪽으로 스와이프를 할 때 동작을 구현할 수 있고, tailing의 경우 그 반대로 스와이프를 할 때 동작을 구현할 수 있는 것이다. 

 

따라서 위 사진을 예로 보자면 오른쪽에서 왼쪽으로 스와이프를 해서 delete 버튼이 활성화되도록 했기 때문에 tableView(_ tableView:trailingSwipeActionsConfigurationForRowAt:) 메서드를 활용한 것이다. 

 

그렇다면 해당 함수 내부는 어떻게 구현해야 하는 것일까?

 

✅ 메서드 내부 구현은 어떻게 할까?

일단 UIContextualAction 타입의 인스턴스를 생성하여 원하는 Action을 생성해주면 된다. 

 

let action = UIContextualAction(style: UIContextualAction.Style, title: String?, handler: UIContextualAction.Handler)
  • style: 해당 액션이 어떻게 나타날 지를 정해주는 것이다. .destructive로 하게 되면 빨간 색의 가장 위 사진처럼 구현할 수 있다.
  • title: 말 그대로 해당 Action이 어떤 타이틀을 가지는지 작성해주면 된다.
  • handler: 해당 액션을 했을 때 어떤 액션이 발생할 지 정해주면 된다. 

 

해당 action의 경우 image나 backgroundColor도 따로 지정해줄 수 있다. 

 

그리고 마지막에는 UISwipeActionsConfiguration을 반환해줘야 하기 때문에 생성한 action들을 배열로 넣고 반환해주면 된다! 

 

func tableView(
    _ tableView: UITableView,
    trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath
) -> UISwipeActionsConfiguration? {
    let deleteAction = UIContextualAction(
        style: .destructive,
        title: Content.swipeDeleteTitle
    ) { [weak self] _, _, _ in
        guard let viewModel = self?.viewModel else { return }
        guard let list = self?.list else { return }

        var selectedWork: Observable<Work?> {
            list.map { $0[safe: indexPath.row] }
        }
        _ = selectedWork.subscribe(onNext: { self?.selectedWork = $0 })

        if let work = self?.selectedWork {
            viewModel.removeWork(work)
        }
    }

    return UISwipeActionsConfiguration(actions: [deleteAction])
}
func tableView(
    _ tableView: UITableView,
    trailingSwipeActionsConfigurationForRowAt indexPath: IndexPath
) -> UISwipeActionsConfiguration? {
    let deleteAction = UIContextualAction(style: .destructive, title: LocalizedString.delete) { _, _, _  in
        if self.isFiltering {
            self.presentDeleteAlert(currentMemo: self.filteredMemos[indexPath.row])
        } else {
            self.presentDeleteAlert(currentMemo: self.memos[indexPath.row])
        }
    }
    let shareAction = UIContextualAction(style: .normal, title: LocalizedString.share) { _, sourceView, _ in
        if self.isFiltering {
            self.presentActivityViewController(currentMemo: self.filteredMemos[indexPath.row], at: sourceView)
        } else {
            self.presentActivityViewController(currentMemo: self.memos[indexPath.row], at: sourceView)
        }
    }
    shareAction.backgroundColor = .systemBlue

    return UISwipeActionsConfiguration(actions: [deleteAction, shareAction])
}

 

Comments