programing

iOS 13에서 검출 시트가 해제되었습니다.

newsource 2023. 4. 20. 21:32

iOS 13에서 검출 시트가 해제되었습니다.

13 이전에는 화면하는 뷰 되었습니다.iOS 13 이전에는 화면 전체를 커버하는 뷰 컨트롤러가 제공되었습니다.된 경우 부모 뷰 " " "viewDidAppear기능이 실행되었습니다.

은 뷰 디폴트로 즉, 즉, "iOS 13"은 "iOS 13"을 의미합니다.viewDidAppear부모 뷰 컨트롤러가 실제로 사라진 적이 없기 때문에 호출되지 않습니다.

제시된 뷰컨트롤러시트가 폐기되었음을 검출할 수 있는 방법이 있습니까?대리인을 사용하지 않고 부모 뷰 컨트롤러에서 재정의할 수 있는 다른 기능이 있습니까?

제시된 뷰컨트롤러시트가 폐기되었음을 검출할 수 있는 방법이 있습니까?

네.

대리인을 사용하지 않고 부모 뷰 컨트롤러에서 재정의할 수 있는 다른 기능이 있습니까?

프레젠테이션 컨트롤러덮어쓰게 .presentationControllerDidDismiss(_:).

https://developer.apple.com/documentation/uikit/uiadaptivepresentationcontrollerdelegate/3229889-presentationcontrollerdiddismiss


표시되는 뷰 컨트롤러가 풀스크린에 관계없이 해제되었음을 알리는 일반적인 런타임 생성 이벤트가 없는 것은 문제가 됩니다.그러나 항상 풀스크린 이외의 뷰 컨트롤러가 존재하기 때문에 새로운 문제는 아닙니다.다만, (iOS 13에는) 더 많이 있습니다!다른 곳에서 이 토픽에 대한 별도의 질의응답(Unified UIView Controller "became frontmost" 검출)을 실시합니다.

다음은 자녀 뷰 컨트롤러가 시트로 표시될 때(기본 iOS 13 방식으로) 해제되는 부모 뷰 컨트롤러의 코드 예입니다.

public final class Parent: UIViewController, UIAdaptivePresentationControllerDelegate
{
  // This is assuming that the segue is a storyboard segue; 
  // if you're manually presenting, just set the delegate there.
  public override func prepare(for segue: UIStoryboardSegue, sender: Any?)
  {
    if segue.identifier == "mySegue" {
      segue.destination.presentationController?.delegate = self;
    }
  }

  public func presentationControllerDidDismiss(
    _ presentationController: UIPresentationController)
  {
    // Only called when the sheet is dismissed by DRAGGING.
    // You'll need something extra if you call .dismiss() on the child.
    // (I found that overriding dismiss in the child and calling
    // presentationController.delegate?.presentationControllerDidDismiss
    // works well).
  }
}

Jerland2의 답변은 (a) 원래 질문자가 시트가 해제되었을 때 함수 호출을 받기를 원했기 때문에 (사용자가 시트를 해제하려고 하면 호출되는 presentationControllerDidAttemptToDismiss를 실장했을 때),(b) isModalInPresentation 설정은 완전히 직교이며, 실제로 제시된 시트를 분해할 수 없습니다(OP가 원하는 것과 반대).

향후 독자를 위해 구현에 관한 보다 완전한 해답은 다음과 같습니다.

  1. 루트 뷰에서 segue를 위한 컨트롤러 준비에서 다음을 추가합니다(모달에 내비게이션 컨트롤러가 있다고 가정).
    // Modal Dismiss iOS 13
    modalNavController.presentationController?.delegate = modalVc
  1. 모달 뷰 컨트롤러에서 다음 대리자 + 메서드를 추가합니다.
// MARK: - iOS 13 Modal (Swipe to Dismiss)

extension ModalViewController: UIAdaptivePresentationControllerDelegate {
    func presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController) {


        print("slide to dismiss stopped")
        self.dismiss(animated: true, completion: nil)
    }
}
  1. 위임 메서드를 호출하려면 모달 뷰 컨트롤러에서 다음 속성이 참인지 확인하십시오.
    self.isModalInPresentation = true
  1. 이익

또 다른 viewWillAppear ★★★★★★★★★★★★★★★★★」viewDidAppear

let vc = UIViewController()
vc.modalPresentationStyle = .fullScreen

이 옵션은 전체 화면을 커버하며 해제 후 위의 메서드를 호출합니다.

사용자가 해당 시트 내에서 모달 시트를 닫을 때 작업을 수행하려는 경우.[닫기(닫기)]가 있는 [(Close)]버튼이 있고@IBAction닫거나 다른 작업을 수행하기 전에 경고를 표시하는 논리입니다.사용자가 이러한 컨트롤러를 누르는 순간을 감지하려고 합니다.

방법은 다음과 같습니다.

class MyModalSheetViewController: UIViewController {

     override func viewDidLoad() {
        super.viewDidLoad()

        self.presentationController?.delegate = self
     }

     @IBAction func closeAction(_ sender: Any) {
         // your logic to decide to close or not, when to close, etc.
     }

}

extension MyModalSheetViewController: UIAdaptivePresentationControllerDelegate {

    func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
        return false // <-prevents the modal sheet from being closed
    }

    func presentationControllerDidAttemptToDismiss(_ presentationController: UIPresentationController) {
        closeAction(self) // <- called after the modal sheet was prevented from being closed and leads to your own logic
    }
}

재빠르다

to (에 대한 일반 솔루션) viewWillAppeariOS13에서

class ViewController: UIViewController {

        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
            print("viewWillAppear")
        }

        //Show new viewController
        @IBAction func show(_ sender: Any) {
            let newViewController = NewViewController()
            //set delegate of UIAdaptivePresentationControllerDelegate to self
            newViewController.presentationController?.delegate = self
            present(newViewController, animated: true, completion: nil)
        }
    }

    extension UIViewController: UIAdaptivePresentationControllerDelegate {
        public func presentationControllerDidDismiss( _ presentationController: UIPresentationController) {
            if #available(iOS 13, *) {
                //Call viewWillAppear only in iOS 13
                viewWillAppear(true)
            }
        }
    }

「」를 .viewWillDisappear UIViewController해고드립니다.isBeingDismissed부울 플래그

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)

    if isBeingDismissed {
        print("user is dismissing the vc")
    }
}

** 사용자가 스와이프 다운 중 카드를 다시 스와이프 업해도 카드가 꺼지지 않더라도 카드가 꺼진 것으로 등록됩니다.하지만 그건 네가 신경 쓰지 않을 수도 있는 사건이야.

DRAG OR Call Discept FUNC는 다음 코드와 함께 작동합니다.

1) root view controller에서 어떤 것이 프레젠테이션 뷰 controller인지 아래 코드와 같이 알립니다.

 override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "presenterID" {
        let navigationController = segue.destination as! UINavigationController
        if #available(iOS 13.0, *) {
            let controller = navigationController.topViewController as! presentationviewcontroller
            // Modal Dismiss iOS 13
            controller.presentationController?.delegate = self
        } else {
            // Fallback on earlier versions
        }
        navigationController.presentationController?.delegate = self

    }
}

2) 다시 루트 뷰 컨트롤러에서 프레젠테이션 뷰 컨트롤러가 분리되었을 때 수행할 작업을 지시합니다.

public func presentationControllerDidDismiss(
  _ presentationController: UIPresentationController)
{
    print("presentationControllerDidDismiss")
}

1) 프리젠테이션 뷰 컨트롤러에서 이 그림에서 취소 또는 저장 버튼을 눌렀을 때아래 코드가 호출됩니다.

self.dismiss(animated: true) {
        self.presentationController?.delegate?.presentationControllerDidDismiss?(self.presentationController!)
    }

여기에 이미지 설명 입력

스위프트에서onDismiss closure를 사용할 수 있는 UI

func sheet<Item, Content>(item: Binding<Item?>, onDismiss: (() -> Void)?, content: (Item) -> Content) -> some View

된 뷰 없는 뷰를 표시할 때 를 할 수 있습니다.modalPresentationStyle로로 합니다.fullScreen 이 중할 수 .

 override func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil) {
    if let _ = viewControllerToPresent as? TargetVC {
        viewControllerToPresent.modalPresentationStyle = .fullScreen
    }
    super.present(viewControllerToPresent, animated: flag, completion: completion)
}

표시된 뷰 컨트롤러가 네비게이션컨트롤러이고 루트컨트롤러를 체크하는 경우,는 위의 조건을 다음과 같이 변경할 수 있습니다.

if let _ = (viewControllerToPresent as? UINavigationController)?.viewControllers.first as? TargetVC {
   viewControllerToPresent.modalPresentationStyle = .fullScreen
}

FullScreen에서 ModalPresentationStyle을 사용한 경우 컨트롤러의 동작은 평소와 같습니다.

ConsultarController ControllerConsultar = 이 항목.스토리보드InstantiateViewController("ConsultarController")를 ConsultarController, Controller Consultar로 지정합니다.ModalPresentationStyle = UIModalPresentationStyle.풀스크린, 이거.네비게이션 컨트롤러PushViewController(ControllerConsultar, True);

제 관점에서는 애플은 이 설정을pageSheet는 디폴트입니다.modalPresentationStyle

가져오고 싶습니다fullScreen를 사용하여 스타일을 기본값으로 되돌리다swizzling

다음과 같이 합니다.

private func _swizzling(forClass: AnyClass, originalSelector: Selector, swizzledSelector: Selector) {
    if let originalMethod = class_getInstanceMethod(forClass, originalSelector),
       let swizzledMethod = class_getInstanceMethod(forClass, swizzledSelector) {
        method_exchangeImplementations(originalMethod, swizzledMethod)
    }
}

extension UIViewController {

    static func preventPageSheetPresentationStyle () {
        UIViewController.preventPageSheetPresentation
    }

    static let preventPageSheetPresentation: Void = {
        if #available(iOS 13, *) {
            _swizzling(forClass: UIViewController.self,
                       originalSelector: #selector(present(_: animated: completion:)),
                       swizzledSelector: #selector(_swizzledPresent(_: animated: completion:)))
        }
    }()

    @available(iOS 13.0, *)
    private func _swizzledPresent(_ viewControllerToPresent: UIViewController,
                                        animated flag: Bool,
                                        completion: (() -> Void)? = nil) {
        if viewControllerToPresent.modalPresentationStyle == .pageSheet
                   || viewControllerToPresent.modalPresentationStyle == .automatic {
            viewControllerToPresent.modalPresentationStyle = .fullScreen
        }
        _swizzledPresent(viewControllerToPresent, animated: flag, completion: completion)
    }
}

그리고 나서 이 줄을 당신의 몸에 붙입니다.AppDelegate

UIViewController.preventPageSheetPresentationStyle()

presentingViewController.viewApply?를 호출하면 쉽게 해제할 수 있지 않을까요?

self.presentingViewController?.viewWillAppear(false)
self.dismiss(animated: true, completion: nil)

언급URL : https://stackoverflow.com/questions/56568967/detecting-sheet-was-dismissed-on-ios-13