UIViewControllerContextTransitioning을 사용하여“From View Controller”가 사라집니다. 만 보입니다. -(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{

한 가지 문제가 있으며 아래에 설명했습니다.

UIViewControllerContextTransitioning사용자 지정 전환에 사용 하고 있습니다.

두 개의 뷰 컨트롤러, 첫 번째 뷰 컨트롤러와 두 번째 뷰 컨트롤러가 있습니다.

이제 애니메이션과 함께 첫 번째 뷰 컨트롤러에 두 번째 뷰 컨트롤러를 추가하고 싶습니다. 이제 두 번째 뷰 컨트롤러가 투명하므로 두 번째 뷰 컨트롤러 아래에서 첫 번째 뷰 컨트롤러를 볼 수 있습니다.

하지만 첫 번째 뷰 컨트롤러가 보이지 않고 두 번째 뷰 컨트롤러 아래에는 검은 색 화면 만 보입니다.

-(void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext{
    self.transitionContext = transitionContext;
    if(self.isPresenting){
        [self executePresentationAnimation:transitionContext];
    }
    else{
       [self executeDismissalAnimation:transitionContext];
    }
  }

-(void)executePresentationAnimation:(id<UIViewControllerContextTransitioning>)transitionContext{
     UIView* inView = [transitionContext containerView];
     UIViewController* toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

     UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];

     CGRect offScreenFrame = inView.frame;
     offScreenFrame.origin.y = inView.frame.size.height;
     toViewController.view.frame = offScreenFrame;

    toViewController.view.backgroundColor = [UIColor clearColor];
    fromViewController.view.backgroundColor = [UIColor clearColor];
    inView.backgroundColor = [UIColor  clearColor];
    [inView insertSubview:toViewController.view aboveSubview:fromViewController.view];
     // [inView addSubview:toViewController.view];
    CFTimeInterval duration = self.presentationDuration;
    CFTimeInterval halfDuration = duration/2;

    CATransform3D t1 = [self firstTransform];
    CATransform3D t2 = [self secondTransformWithView:fromViewController.view];

    [UIView animateKeyframesWithDuration:halfDuration delay:0.0 options:UIViewKeyframeAnimationOptionCalculationModeLinear animations:^{

    [UIView addKeyframeWithRelativeStartTime:0.0f relativeDuration:0.5f animations:^{
        fromViewController.view.layer.transform = t1;
    }];

    [UIView addKeyframeWithRelativeStartTime:0.5f relativeDuration:0.5f animations:^{
        fromViewController.view.layer.transform = t2;
    }];
    } completion:^(BOOL finished) {
    }];


    [UIView animateWithDuration:duration delay:(halfDuration - (0.3*halfDuration)) usingSpringWithDamping:0.7f initialSpringVelocity:6.0f options:UIViewAnimationOptionCurveEaseIn animations:^{
        toViewController.view.frame = inView.frame;
    } completion:^(BOOL finished) {
        [self.transitionContext completeTransition:YES];
    }];
}

경우 [self.transitionContext completeTransition:YES];라고 갑자기 제 뷰 컨트롤러가 사라지고 초 뷰 컨트롤러 아래에 블랙 스크린 디스플레이.

아무도 아이디어가 있습니까? 감사.



답변

여기서도 같은 문제가 발생했습니다. iOS 8의 버그처럼 보입니다 . 레이더를 제출했습니다 .

화면이 검게 변한 후 Reveal 을 사용 하여 뷰 계층 구조를 검사했습니다. 키 UIWindow는 완전히 비어 있습니다. 뷰 계층 구조가 전혀 없습니다!

나는 약간 놀았고 간단한 경우에 쉬운 해결 방법이있는 것 같습니다. toViewController의보기를 키 창의 하위보기로 다시 추가 할 수 있습니다 .

transitionContext.completeTransition(true)
UIApplication.sharedApplication().keyWindow!.addSubview(toViewController.view)

나는 확인했고 키 창 rootViewController은 여전히 ​​올바르게 설정되어 있으므로 괜찮습니다. 이미 제시된 모달 컨트롤러 내에서 컨트롤러를 제시하면 어떻게 될지 잘 모르겠습니다. 따라서 더 복잡한 경우에는 여러 가지 실험을해야합니다.


답변

나는 이것의 이유가 더 잘 설명되어야한다고 생각한다.

표시하는 뷰 컨트롤러의 뷰를 원래 위치 (뷰 계층 구조)에서 꺼내서 애니메이터가 제공하는 containerView 안에 넣지 만 애니메이션이 완료된 후에는 다시 반환하지 않기 때문에 뷰가 사라집니다. 따라서 뷰 컨트롤러의 뷰는 창에서 수퍼 뷰 (containerView)와 함께 완전히 제거됩니다.

iOS 7에서 시스템은 전환이 자동으로 애니메이션을 마친 후 항상 프레젠테이션 (프레젠테이션 및 프레젠테이션)에 관련된 뷰 컨트롤러의 뷰를 원래 위치로 반환했습니다. iOS 8의 일부 프레젠테이션 스타일에서는 더 이상 발생하지 않습니다.

규칙은 매우 간단합니다. 애니메이터는 전환끝날 때 뷰 컨트롤러의 뷰가 완전히 숨겨 질 경우 (뷰 계층에서 제거됨) 프레젠테이션 뷰 컨트롤러의 뷰만 조작해야합니다 . 즉, 초기 프리젠 테이션 애니메이션이 완료된 후에는 프리젠 테이션 뷰 컨트롤러의 뷰가 아니라 제시된 뷰 컨트롤러의 뷰만 표시됩니다. 예를 들어 제시된 뷰 컨트롤러의 뷰의 불투명도를 50 %로 설정하고 UIModalPresentationFullScreen을 사용하면 제시된 뷰 컨트롤러의 뷰를 제시하는 것을 볼 수 없지만 UIModalPresentationOverFullscreen을 사용하면 (UIPresentationController의 shouldRemovePresentersView메서드가이를 지정합니다).

애니메이터가 프리젠 테이션 뷰 컨트롤러의 뷰를 항상 조작하도록 허용하지 않는 이유는 무엇입니까? 우선, 프리젠 테이션 뷰 컨트롤러의 뷰가 전체 프리젠 테이션 수명주기 동안 애니메이션이 끝난 후에도 계속 보이게 될 경우에는 애니메이션을 적용 할 필요가 없습니다. 그대로 유지됩니다. 둘째, 해당 뷰 컨트롤러의 소유권이 프레젠테이션 컨트롤러로 전송되면 프레젠테이션 컨트롤러는 방향이 변경 될 때와 같이 필요할 때 해당 뷰 컨트롤러의 뷰를 레이아웃하는 방법을 알지 못하지만 프레젠테이션 뷰 컨트롤러의 원래 소유자는 .

iOS 8에서는 viewForKey:애니메이터가 조작하는 뷰를 가져 오는 방법이 도입되었습니다. 첫째, 애니메이터가 뷰를 터치하지 않아야 할 때마다 nil을 반환함으로써 위에서 설명한 규칙을 따르는 것이 도움이됩니다. 둘째, 애니메이터가 애니메이션 할 수 있도록 다른 뷰를 반환 할 수 있습니다 . 양식 시트와 유사한 프레젠테이션을 구현한다고 가정 해보십시오. 이 경우 제시된 뷰 컨트롤러의 뷰 주변에 그림자 나 장식을 추가하고 싶을 것입니다. 애니메이터는 대신 해당 장식을 애니메이션하고 표시된 뷰 컨트롤러의 뷰는 장식의 자식이됩니다.

viewControllerForKey: 사라지지 않습니다. 뷰 컨트롤러에 대한 직접 액세스가 필요하지만 애니메이터는 애니메이션에 필요한 뷰에 대해 어떤 가정도해서는 안됩니다.

애니메이터의 컨테이너 뷰 내부에 명시 적으로 배치 할 때 표시되는 뷰 컨트롤러의 뷰가 사라지는 문제 를 올바르게 수정하기 위해 수행 할 수있는 몇 가지 작업이 있습니다 .

  1. 프리젠 테이션 뷰 컨트롤러의 뷰를 애니메이션 할 필요가없는 경우 viewForKey:컨트롤러의 뷰를 직접 보는 대신 애니메이션 할 뷰를 가져 오는 데 사용합니다. viewForKey:nil 또는 완전히 다른 뷰를 반환 할 수 있습니다.

  2. 제시하는 뷰 컨트롤러의 뷰에 애니메이션을 적용하려면 UIModalPresentationFullScreen스타일 사용을 고려 UIModalPresentationCustom하거나을 shouldRemovePresentersView반환 하는 UIPresentationController의 자체 하위 클래스를 계속 사용 하고 구현해야합니다 YES. 실제로이 방법의 구현은에서 정의한 내부 프레젠테이션 컨트롤러 UIModalPresentationFullScreenUIModalPresentationCustom스타일 간의 주요 차이점 입니다. 후자는 사용자 지정 프레젠테이션 컨트롤러를 사용할 수 있다는 사실을 제외하고는 다릅니다 .

  3. 다른 모든 드문 경우에 다른 답변이 제안한대로 프레젠테이션 뷰 컨트롤러의 뷰를 원래 위치로 되돌려 야합니다.


답변

iOS 8에서는에서 반환 한 뷰 컨트롤러 viewForKey:.view속성 대신에서 반환 한 뷰를 조작해야합니다 viewControllerForKey:. 이것은 베타 문서에서 특히 명확하지 않지만 UIViewControllerTransitioning.h의 소스를 살펴보면 위의 주석을 볼 수 있습니다 viewControllerForKey:.

// Currently only two keys are defined by the
// system - UITransitionContextToViewControllerKey, and
// UITransitionContextFromViewControllerKey.
// Animators should not directly manipulate a view controller's views and should
// use viewForKey: to get views instead.
- (UIViewController *)viewControllerForKey:(NSString *)key;

따라서의 프레임 등을 조정하는 대신의 toViewController.view반환 값을 사용하십시오 [transitionContext viewForKey:UITransitionContextToViewKey].

앱이 iOS7 및 / 또는 Xcode 5를 지원해야하는 경우 다음과 같이 UIViewController에서 간단한 카테고리 메서드를 사용할 수 있습니다.

- (UIView *)viewForTransitionContext:(id<UIViewControllerContextTransitioning>)transitionContext
{
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
    if ([transitionContext respondsToSelector:@selector(viewForKey:)]) {
        NSString *key = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey] == self ? UITransitionContextFromViewKey : UITransitionContextToViewKey;
        return [transitionContext viewForKey:key];
    } else {
        return self.view;
    }
#else
    return self.view;
#endif
}

그런 다음 평소 toViewControllerfromViewController같이 및 을 가져 오지만 [toViewController viewForTransitionContext:transitionContext].

편집 :에서 반환 될 때 프레젠테이션보기 컨트롤러의보기가 nil 인 버그가있는 것으로 보입니다 viewForKey. 이로 인해 프레젠테이션보기를 전혀 애니메이션화하는 모달 전환 (예 : 슬라이드 끄기 또는 뒤집기)을 만들 수 없습니다. rdar : // 17961976 ( http://openradar.appspot.com/radar?id=5210815787433984 ) 에서 iOS8에 대한 버그를 신고했습니다 . http://github.com/bcherry/TransitionBug 에서 샘플 프로젝트도 참조하십시오.

편집 2 : 제안에 대한 graveley 덕분에 UIModalPresentationFullScreen을 사용하여 문제를 해결합니다. 아마도 이것은 버그가 아닙니다. Apple은 UIModalPresentationCustom이 들어오는 모달의보기 만 수정하도록 의도 할 수 있습니다. 나가는보기를 수정하려면 새보기의 전체 화면 표시를 보장해야합니까? viewForKey어쨌든 UIModalPresentationFullScreen 을 사용해야합니다 .


답변

modalPresentationStyleUIModalPresentationCustom으로 설정하지 않으면 문제가 해결되었습니다.

즉, UIModalPresentationCustom을 지정하는 대신 기본값 인 UIModalPresentationFullScreen을 그대로두면 사라지는보기 문제가 해결되었습니다. UIViewControllerTransitioningDelegate 프로토콜은 기본값으로 두더라도 여전히 따르는 것처럼 보입니다. 내가 올바르게 기억한다면, 옛날 옛적에 UIModalPresentationCustom이 요구 사항이었습니다.

지금까지 작동하는 작업은 비대화 형 애니메이션에 대해서만 시도했습니다.


답변

Lefteris의 관련 스레드에서이 매우 유용한 답변을 찾았습니다.
https://stackoverflow.com/a/27165723/3709173

그것을 요 ​​약하기:

  1. modalPresentationStyle을 .Custom으로 설정하십시오.
  2. 하위 클래스 UIPresentationController, shouldRemovePresentersView 재정의 (NO)
  3. TransitionDelegate 클래스에서 presentationControllerForPresentedViewController를 재정의하고 사용자 지정 UIPresentationController를 반환합니다.

사용자 지정 전환에 +1하고, 해제 애니메이션이 발생할 때 toView를 추가하지 마세요.

여기에서 설명 :


해킹없이 https://www.dropbox.com/s/7rpkyamv9k9j18v/CustomModalTransition.zip?dl=0 ! 마법 같아! 🙂


답변

iOS 8에서는 UIPresentationController를 생성하고 UIViewControllerTransitioningDelegate에서 아래 메서드를 구현해야합니다.

- (UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source;

뷰 컨트롤러를 표시 할 때 뷰 계층을 관리하는 데 사용할 사용자 지정 프레젠테이션 컨트롤러를 대리인에게 요청합니다.

반환 값 :

모달 프레젠테이션을 관리하기위한 사용자 지정 프레젠테이션 컨트롤러입니다.

토론:

UIModalPresentationCustom 프레젠테이션 스타일을 사용하여 뷰 컨트롤러를 표시하면 시스템이이 메서드를 호출하고 사용자 지정 스타일을 관리하는 프레젠테이션 컨트롤러를 요청합니다. 이 메서드를 구현하는 경우이를 사용하여 프레젠테이션 프로세스를 관리하는 데 사용할 사용자 지정 프레젠테이션 컨트롤러 개체를 만들고 반환합니다.

이 메서드를 구현하지 않거나이 메서드의 구현이 nil을 반환하는 경우 시스템은 기본 프레젠테이션 컨트롤러 개체를 사용합니다. 기본 프리젠 테이션 컨트롤러는보기 계층 구조에보기 또는 컨텐츠를 추가하지 않습니다.

iOS 8.0 이상에서 사용 가능합니다.

자세한 내용은 WWDC 2014 비디오를 시청하십시오.

https://developer.apple.com/videos/wwdc/2014/?include=228

WWDC 2014 샘플 코드 페이지에서 다운로드 할 수있는 “LookInside : Presentation Controllers Adaptivity and Custom Animator Objects”라는 WWDC의 샘플 코드도 있습니다.

샘플 코드를 약간 변경해야 할 수도 있습니다. UIPresentationController init 메소드가 다음과 같이 변경되었습니다.

initWithPresentedViewController:presented presentingViewController:presenting

발표하기 전에 발표했습니다. 그것들을 바꾸면 작동합니다.


답변

[inView insertSubview : toViewController.view aboveSubview : fromViewController.view] 대신; 그냥 추가하십시오 : [inView addSubview : toViewController.view];

if (self.presenting) {

    [transitionContext.containerView addSubview:toViewController.view];
    // your code

} else {
    // your code
}

여기에서 예제를 볼 수 있습니다. 링크 는 iOS 7 및 iOS 8에서 작동합니다.