ios - 컴퓨팅 사고력 키우기




사용자 정의보기 컨트롤러 프레젠테이션을 구현할 때 제시된보기의 제약 조건을 적용 할 위치는 무엇입니까? (2)

나는 현재 프로젝트에서 double-height statusBar로 어려움을 겪어 왔고 거의 모든 이슈를 해결할 수있었습니다 (마지막 나머지 하나는 presentingViewController가 UITabBarController 내부에 포함될 때 매우 이상한 변환 문제입니다).

상태 표시 줄의 높이가 변경되면 알림이 게시됩니다.
UIPresentationController 하위 클래스는 해당 특정 알림을 구독 하고 containerView 및 해당 하위 뷰의 프레임을 조정해야합니다.

UIApplication.willChangeStatusBarFrameNotification

다음은 사용중인 코드의 예입니다.

final class MyCustomPresentationController: UIPresentationController {

    // MARK: - StatusBar

    private func subscribeToStatusBarNotifications() {
        let notificationName = UIApplication.willChangeStatusBarFrameNotification
        NotificationCenter.default.addObserver(self, selector: #selector(statusBarWillChangeFrame(notification:)), name: notificationName, object: nil)
    }

    @objc private func statusBarWillChangeFrame(notification: Notification?) {
        if let newFrame = notification?.userInfo?[UIApplication.statusBarFrameUserInfoKey] as? CGRect {
            statusBarWillChangeFrame(to: newFrame)
        } else {
            statusBarWillChangeFrame(to: .zero)
        }
    }

    func statusBarWillChangeFrame(to newFrame: CGRect) {
        layoutContainerView(animated: true)
    }

    // MARK: - Object Lifecycle

    deinit {
        // Unsubscribe from all notifications
        NotificationCenter.default.removeObserver(self)
    }

    // MARK: - Layout

    /// Called when the status-bar is about to change its frame.
    /// Relayout the containerView and its subviews
    private func layoutContainerView(animated: Bool) {
        guard let containerView = self.containerView else { return }

        // Retrieve informations about status-bar
        let statusBarHeight = UIApplication.shared.statusBarFrame.height
        let normalStatusBarHeight = Constants.Number.statusBarNormalHeight // 20
        let isStatusBarNormal = statusBarHeight ==~ normalStatusBarHeight

        if animated {
            containerView.frame = …
            updatePresentedViewFrame(animated: true)
        } else {
            // Update containerView frame
            containerView.frame = …
            updatePresentedViewFrame(animated: false)
        }
    }

    func updatePresentedViewFrame(animated: Bool) {
        self.presentedView?.frame =}
}

커스텀 모달 프리젠 테이션에 대한 Apple의 모든 문서를 읽었으며이 대답을 찾을 수 없었습니다. 사용자 정의 애니메이션을 사용하여보기 컨트롤러를 표시 할 때 우리는 3 가지를 반환 할 수 있습니다 (전환이 대화 형이 아닌 경우 대화 형은 4를 반환 할 수 있음) : 프레젠테이션 컨트롤러와 애니메이션 컨트롤러 두 개 (현재와 해제 중 하나).

프레젠테이션 컨트롤러와 현재 애니메이션 컨트롤러 모두 Apple 코드에는 제약 조건이 없습니다. 프레임에 대한 논의의 범위는 현재 애니메이션 컨트롤러 (아래)에서 제시된 뷰 컨트롤러의 뷰 프레임을 설정하는 Apple의 권장 사항입니다.

// Always add the "to" view to the container.
// And it doesn't hurt to set its start frame.
[containerView addSubview:toView];
toView.frame = toViewStartFrame;

...그리고 그게 다야.

내가 가진 문제는 이중 높이 상태 표시 줄이 시뮬레이터 (및 내가 소유 한 장치)의 제시된보기 컨트롤러에 의해 인식되지 않는다는 것입니다. 더 정확히 말하면 모든 시뮬레이터에서 단일 솔루션이 작동하지 않습니다. 새로운 시뮬레이터 (iPhone 8과 같은)에서 작동하는 솔루션은 이전 시뮬레이터 (iPhone 5와 같은)에서는 작동하지 않습니다. Apple이 기본 UIKit 애니메이션을 사용하여 프리젠 테이션을 처리하도록하면 두 번 높이의 상태 표시 줄이 제시된 뷰 컨트롤러에서 잘 처리됩니다. 따라서 제시된 뷰 컨트롤러의 제약이 문제가 아니라고 가정 할 수 있습니다.

그래서 프리젠 테이션 컨트롤러의 containerViewDidLayoutSubviewscontainerViewWillLayoutSubviews 메서드를 사용하면 아무런 문제가 없습니다.

override func containerViewDidLayoutSubviews() {
    super.containerViewDidLayoutSubviews()
    presentedViewController.view.frame = containerView!.bounds
}

위의 코드는 처음으로 이중 높이 상태 표시 줄이 도입되었을 때만 시뮬레이터에서 작동합니다. 거기서부터이 방법은 반응이 없습니다. 이를 확인하려면 다음을 수행하십시오.

override func containerViewDidLayoutSubviews() {
    super.containerViewDidLayoutSubviews()
    presentedViewController.view.frame = containerView!.bounds
    print("did layout")
}

위의 방법은 이중 높이 상태 표시 줄을 처음 도입 한 후 콘솔로 인쇄를 중지합니다. 그러나 내가 제시 한 뷰 프레임의 크기를 변경하지 않는 것으로, 예를 들어 배경색을 변경하는 등의 작업을 변경하면 :

override func containerViewDidLayoutSubviews() {
    super.containerViewDidLayoutSubviews()
    presentedViewController.view.backgroundColor = UIColor.blue
    print("did layout")
}

방법은 결코 깨지지 않는다. 어떤 이유로 든이 메서드에서 표시된 뷰 프레임의 크기를 변경하면 이중 높이 상태 표시 줄을 처음 전환 한 후에 메서드가 중단됩니다. 나는이 행동에 대한 설명을 좋아할 것이다. 있을 법하지는 않지만 버그처럼 보입니다.

어쨌든, 애플은 자동 레이아웃이 올바르게 사용된다면 프로그래머는 아무 것도 할 필요가 없다고 말한다. 그래서 내 질문은, 어디에 또는 어떻게 우리는 임시 컨트롤러에 적응할 수 있도록 제시 컨트롤러의 뷰 제약 조건을 제시해야합니까? 왜냐하면, IMO, 그게 문제 야. 표시된 뷰 컨트롤러는 UIKit에서 제공하는 임시보기 인 전환의 컨테이너보기에서 소유하므로 많은 권한이 없습니다. 제시된 뷰를 해당 컨테이너에 앵커링 할 수 있으면 모든 문제가 해결됩니다. 그러나 나는 애플이 이것을하거나 심지어 이것에 대해서 이야기하는 것을 본 적이 없다.

참고 : 명시된 뷰를 컨테이너 뷰 (애니메이션 또는 완성 처리기 이전의 현재 애니메이터 컨트롤러, 프레젠테이션 컨트롤러 또는 적응 형 대리자 메서드)에 명시 적으로 고정하면 언급 된 일관된 결과가 생성되지 않습니다 일찍이.

결론 : (1) 모달 프리젠 테이션으로 공식적으로, 적절하게, 깔끔하게, 또는 일관되게 다기능 상태 표시 줄을 처리 할 방법이 없습니다. (2) Apple은 이중 높이 상태 표시 줄을 사용하여 그것을 훼손했으며 모든 iPhones가 화면에 노치가있는 날을 기다릴 수 없습니다.


내 대답은 : 당신은 사용자 정의 모달 프레 젠 테이션의 경우 제약을 사용해서는 안됩니다

그러므로 나는 당신의 고통을 안다. 그래서 내가 갑자기 드러낸 몇 가지 힌트를 제공함으로써 당신이 시간과 노력을 절약 할 수 있도록 도울 것이다.

예 :

다음과 같은 카드 UI 애니메이션 :

추가 이용 약관 :

  • 부모 - "자세히"막대 단추 항목이있는 UIViewController
  • 하위 - "다른" UIViewController

언급 한 문제는 애니메이션과 함께 크기가 변할 때부터 시작되었습니다. 그것은 다음과 같은 다른 종류의 효과를 일으킨다.

  • 부모의 과소 상태 표시 줄 영역이 나타나고 사라졌습니다.
  • 학부모의 하위 뷰는 점프, 복제 및 기타 결함이 생생하게 애니메이션되었습니다.

몇 일간의 디버깅과 검색 후에 다음과 같은 해결책을 찾았습니다. (일부 마법 번호는 유감입니다;)) :

UIView.animate(withDuration: transitionDuration(using: transitionContext),
                       delay: 0,
                       usingSpringWithDamping: 1,
                       initialSpringVelocity: 0.4,
                       options: .curveEaseIn, animations: {
            toVC.view.transform = CGAffineTransform(translationX: 0, y: self.finalFrame.minY)
            toVC.view.frame = self.finalFrame
            toVC.view.layer.cornerRadius = self.cornerRadius

            fromVC.view.layer.cornerRadius = self.cornerRadius
            var transform = CATransform3DIdentity
            transform = CATransform3DScale(transform, scale, scale, 1.0)
            transform = CATransform3DTranslate(transform, 0, wdiff, 0)
            fromVC.view.layer.transform = transform
            fromVC.view.alpha = 0.6
        }) { _ in
            transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
        }

여기서 중요한 점은 CGAffineTransform3D 를 사용하여 애니메이션 문제 및 하위 뷰 애니메이션 문제 ( 2D 변환 은 알 수없는 이유로 작동하지 않음)를 피할 수 있다는 것입니다.

이 접근법은 제약 조건을 사용하지 않고 모든 문제를 해결합니다.

부담없이 질문하십시오.

UPD : In-Call 상태 표시 줄에 따라

모든 가능한 실험 시간과 this 과 이와 비슷한 질문을 검토 한 결과, this (실제로 재미 있고, OP 답변도 있습니다) 그리고 비슷하게 나는 완전히 혼란 스럽습니다. 내 솔루션처럼 UIKit 수준 (적절하게 조정)에 Double 상태 표시 줄을 처리하는 것처럼 보이지만 동일한 동작은 이전 변환을 무시합니다. 이유는 알려져 있지 않습니다.

코드 샘플 :

Github 에서 실제 해결책을 볼 수 있습니다.

추신 : 답변에 GitHub 링크를 게시해도 괜찮은지 잘 모르겠습니다. 내가 답변을 100-300 라인 코드를 게시하는 방법에 대한 조언을 주셔서 감사하겠습니다.





autolayout