iOS Modal 아래로 스크롤 동작 감지하기

Groot·2022년 12월 19일
0

TIL

목록 보기
118/153
post-thumbnail
post-custom-banner

TIL

🌱 난 오늘 무엇을 공부했을까?

📌 iOS Modal 아래로 스크롤 동작 감지하기

  • 내용이 수정이 된 상태에서 저장하지 않고 아래로 스크롤을 통해 View를 Dissmiss 하면 사용자가 수정한 내용이 사라지는 문제를 해결하기 위해 방법을 찾아봤다.

📌 Disabling the Pull-Down Gesture for a Sheet

  • UIKit을 사용하면 사용자가 데이터나 최근 변경 사항을 잃을 수 있는 상황에서 풀다운 제스처를 비활성화할 수 있다.
  • 사용자가 UIAlertController의 인스턴스를 표시하여 보기 컨트롤러 표시를 닫을 수 없는 이유를 설명할 수도 있다.

📍 Disable the Ability to Dismiss a Presentation

  • Pull-Down Gesture를 통해 뷰 컨트롤러 프레젠테이션 Dissmiss를 비활성화하려면 modalInPresentation을 true로 설정한다.
    • modalInPresentation
      • 뷰 컨트롤러가 모달 동작을 적용하는지 여부를 나타내는 부울 값.
      • 기본값은 NO.
      • YES로 설정하면 UIKit은 뷰 컨트롤러 범위 밖의 이벤트를 무시하고 화면에 있는 동안 뷰 컨트롤러의 interactive dismissa를 방지. <- 오늘의 핵심
isModalInPresentation = hasChanges

📍 Explain Why the User Can’t Dismiss a Presentation

  1. 사용자가 아래로 스크롤을 내렸을 때 특정 작업을 수행하려면 아래 코드와 같이 프레젠테이션의 대리자를 설정

    UIPresentationController : 뷰 컨트롤러가 표시되는 시간부터 닫힐 때까지 UIKit은 프레젠테이션 컨트롤러를 사용하여 해당 뷰 컨트롤러에 대한 프레젠테이션 프로세스의 다양한 측면을 관리.

  • 예시코드
    self.presentationController?.delegate = editViewController // present 방식일 때
  1. PresentationControllerDidAttemptToDismiss:를 구현하고 작업을 수행
  • 예시코드
func presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController) {
    // 시스템은 사용자가 Dissmiss 동작을 시도할 때마다 이 대리자 메서드를 호출합니다.
    // 'isModalInPresentation'이 false면 이 메서드는 작동하지 않고 바로 Dissmiss. 
    // 취소 또는 저장 여부를 물어 사용자에게 선택 할 수 있게 한다.
        내가 원하는 작업
    }

📍 실제 적용

  • delegate 선언.
override func viewDidLoad() {
        super.viewDidLoad()
        self.presentationController?.delegate = self
}
  • 하위뷰 레이아웃 변경을 감지해서 그때마다 isModalInPresentation의 값을 설정.
override func viewWillLayoutSubviews() {
       isModalInPresentation= updateView.hasChangesModel()
}
  • Pull-Down Gesture를 감지해서 내용변경 시 Sheet를 보여줌.
extension UpdateViewController: UIAdaptivePresentationControllerDelegate {
    func presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController) {
        if updateView.hasChangesModel() {
            let alertController = UIAlertController(title: "", message: "변경 사항을 폐기할까요?", preferredStyle: .actionSheet)
            let disposeAction = UIAlertAction(title: "변경 사항 폐기", style: .default) { [weak self] _ in self?.dismiss(animated: true) }
            let cancelAction = UIAlertAction(title: "계속 편집하기",  style: .destructive) { _ in return }
            alertController.addAction(disposeAction)
            alertController.addAction(cancelAction)
            present(alertController, animated: true)
            
            return
        }
        
        dismiss(animated: true)
    }
}

🔗 미해결 문제

  • 가장 상단의 TextField의 내용을 변경하면 상위 뷰컨의 viewWillLayoutSubviews()가 호출이 되었다. 하지만, 하단에 있는 TextView와 SegmentedControl의 내용 변경에는 호출되지 않았다.
  • 무엇이 문제일까...? 해답을 찾게되면 수정해야겠다.

📍 적용화면

  • 수정 전 화면
  • 수정 후 화면
profile
I Am Groot
post-custom-banner

0개의 댓글