UIViewControllerContextTransitioning을 사용하여“From View Controller”가 사라집니다.


105

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

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];라고 갑자기 제 뷰 컨트롤러가 사라지고 초 뷰 컨트롤러 아래에 블랙 스크린 디스플레이.

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

답변:


98

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

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

Reveal'd

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

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

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


2
나는 또한이 문제를 보았다. iOS 8에는 fromView 및 toView에 액세스하기위한 새로운 방법과 키가 도입되었습니다 (참고 :보기 컨트롤러가 아님) 전환 중에 이러한 참조가 손실되지 않는 것처럼 보입니다. 뷰 컨트롤러에서 방금 검색 한 경우 일반적인 방식으로 컨테이너 뷰에 추가 할 수 있습니다.
TAPI

1
viewDidLoad에서 내 탐색 컨트롤러의보기에 하위보기를 추가하려고 할 때 비슷한 iOS 8 이상 함을 보았습니다. navigationController의 뷰를 keyWindow에 다시 추가하는 것이 트릭을하는 것처럼 보였습니다. 감사합니다. Ash!
테이 버

1
나는 여전히 GM에서 이것을보고있다 (그리고이 수정은 여전히 ​​작동한다). 다른 사람들도 똑같이보고 있습니까? 이것은 단지 API의 변경입니까?
rjkaplan 2014 년

21
설정하면이 버그 (및 더 많은 것)가 사라진다는 것을 발견했습니다 modalPresentationStyle = UIModalPresentationFullScreen. 물론 사용자 정의 전환 애니메이션을 얻을 수 있습니다.
Chris

1
감사합니다 @AshFurrow. 수정 될 때까지 좋은 해결 방법!
kandelvijaya

78

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

표시하는 뷰 컨트롤러의 뷰를 원래 위치 (뷰 계층 구조)에서 꺼내서 애니메이터가 제공하는 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. 다른 모든 드문 경우에 다른 답변이 제안한대로 프레젠테이션 뷰 컨트롤러의 뷰를 원래 위치로 되돌려 야합니다.


2
이 코드 는 nil을 반환 할 때만 viewControllerForKey:s에 의존 하기 때문에 매우 이상 합니다. 그리고 여전히 수동으로 창에 다시 추가해야했습니다. 이 해결 방법없이 작동하는 코드의 예가 있습니까? viewviewForKey:
Ash Furrow

글쎄, viewForKey:nil을 반환하면 애니메이터에서 제거하면 프레젠테이션 뷰 컨트롤러의 뷰를 창에 다시 추가해야합니다. viewForKey가 실제 뷰 컨트롤러의 뷰를 반환하는 경우 UIKit이 프레젠테이션 수명주기가 끝난 후 원래 위치로 다시 이동하므로 해당 뷰를 이동하는 것이 안전합니다.
egdmitry 2014 년

이 문제의 원인을 설명해 주셔서 감사합니다. 당신이 절대적으로 옳습니다. 뷰 계층 구조에서 뷰의 위치를 ​​바꾸지 않고 이동하면 분명히 사라질 것입니다 (iOS 8 이후, 지금 iOS 10으로 작업 중입니다!). 명확히 해주셔서 감사합니다.
Clay Ellis

1
설명해 주신 egdmitry에게 감사드립니다. 또 다른 질문이 제기됩니다. 공개 와 같은 프레젠테이션을 어떻게 구현해야한다고 생각 하십니까? 오늘날 프리젠 테이션 뷰가 부분적으로 슬라이드되어 아래에 제시된 뷰를 표시하는 매우 일반적인 것 중 하나는 무엇입니까? 이 시나리오에서는 프레젠테이션보기와 프레젠테이션보기가 모두 화면에 있어야하며 프레젠테이션보기는 애니메이션보기입니다.
Andrea

70

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 을 사용해야합니다 .


2
viewForKey 버그는 나를 미치게 만들었습니다! — 제출해 주셔서 감사합니다. FWIW 내 전환은 UITransitionContextToViewControllerKey에서 뷰를 가져와 제대로 작동하지만 전환은 전체 뷰에만 변환을 적용합니다. 나는 그것이 manipulating벤처 캐피탈의 견해 로 해석되어야하는지 확실 하지 않다 ...
MathewS

1
와우 – 그건 미쳤어. 나는 diff에서 그것을 보지 못했다 – 아마도 그것은 단지 약간의 코멘트이기 때문일 것이다. 애플이 이런 스턴트를 할 때 정말 실망 스럽습니다. 레이더에 손가락이 교차했습니다.
Ash Furrow 2014-08-20

viewForKeyGM에서도 버그를 보고 있습니다. 다른 사람도 있습니까? 이에 대한 적절한 해결 방법을 찾았습니까?
rjkaplan 2014 년

2
- viewForKey// viewForKey :의 주석에 따르면 애니메이터가 연관된 뷰 컨트롤러의 뷰를 조작하지 않아야 함을 나타내는 nil반환 할 수 있다고 생각했습니다 . 반환 nil은 버그가 아닙니다.
Ken Kuan

4
@kenKuan 당신이 맞을 수 있습니다. UIModalPresentationFullScreen을 사용할 때 viewForKeyfrom view와 to view를 반환합니다. 따라서 의도적으로 UIModalPresentationCustom에 대해 nil을 반환 할 수도 있습니다. 버그 보고서를 업데이트하고 있으며 이에 대해 Apple로부터 답장을 받으면 여기에 다시 게시하겠습니다.
bcherry

24

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

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

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


1
와. 그게 해냈어! iOS7 및 8에서 modalPresentationStyle없이 테스트했으며 둘 다에서 작동합니다. 감사!!

1
감사합니다! 이것은 사용과 결합 viewForKey:대신에 .viewviewControllerForKey:나를 위해 모든 문제를 해결합니다.
bcherry

1
이것은 viewForKey를 사용하지 않고 문제를 해결했지만 그것도 사용해야한다고 생각합니다.
Kevin Sliech

5
이것이 문제를 해결하는 것처럼 보이지만 뷰 컨트롤러 뒤의 화면이 일단 표시되면 검은 색으로 변한다는 점에 유의하는 것이 중요합니다. 뷰 컨트롤러가 전체 화면이 아닌 경우 중요합니다.
그 친구는

16

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 ! 마법 같아! :)


1
이것은 실제 정답입니다. 받아 들여진 것과 같은 마술없이. 고마워, 마크!
안드레이 Malygin

안타깝게도 iOS 12.4, Xcode 10.3에서는 작동하지 않습니다. 스크린 뷰는 모든 계층에서 제거 된 (전환 완료되면 검게 그러나 작업 건배 DOES '.fullscreen'에 'modalPresentationStyle'속성을 설정...
움블

내 프로젝트에서 Mark와 gwinyai의 Swift 구현에서 Obj-C 버전을 시도했습니다. 불행히도 그들 중 어느 것도 예상대로 작동하지 않습니다. Xcode 11.1을 사용하고 있으며 빌드 대상은 iOS 13.0이며 장치와 시뮬레이터 모두에서 시도했습니다. 필자의 경우 기본 설정은 컬렉션보기이며 하나의 셀을 탭하면 애니메이션이있는 세부보기로 전환됩니다. 그러나 기본 전환 애니메이션을 사용하면 완전히 잘 작동합니다. 자세히보기에서 다시 시작할 때 발표중인 VC가 사라지지 않습니다.
infinity_coding7

8

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

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


연결된 비디오를 보지 않아서 미안하지만, 애니메이션이 완료된 후 비표준 프레젠테이션을 원하지 않는 한 사용자 정의 UIPresentationController가 필요하지 않다고 생각합니다. 다른 애니메이션을 원하면 제한된 지식을 바탕으로 UIViewControllerAnimatedTransitioning을 구현하는 것으로 충분합니다.
Vaddadi Kartick

7

[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에서 작동합니다.


이것은 fromViewController를 containerView에 추가 할 필요가 없기 때문에 UIModalPresentationStyleCustom 유형의 애니메이션을 수행하는 데 허용되는 답변이어야합니다. 애니메이션을 제공하는 동안 toViewController를 추가하기 만하면됩니다.
Scott Kaiser

이것은 실제로 매우 유용
드미트리 Bondarev

7

다음은 Ash 수정의 Objective C 버전입니다.

// my attempt at obj-c version of Ash's fix
UIView *theToView = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey].view;
[[[UIApplication sharedApplication] keyWindow] addSubview:theToView];
[transitionContext completeTransition:YES]

제대로 작동하려면 다른 뷰 컨트롤러의 해제 완료 블록에서 새 뷰 컨트롤러를 제공하기 위해 뷰를 다시 추가 한 후 순서를 바꾸고 [transitionContext completeTransition :] 메서드를 호출해야했습니다.

이것이 모든 사람에게 문제를 해결할 수 있을지 모르겠지만 내 앱에서는 작동합니다. 건배!


5

나는 이것이 Obj-C에서 잘 작동한다는 것을 알았습니다.

    [transitionContext completeTransition:YES];
    if(![[UIApplication sharedApplication].keyWindow.subviews containsObject:toViewController.view]) {
        [[UIApplication sharedApplication].keyWindow addSubview:toViewController.view];
    }

ios7과 ios8 모두에서 잘 작동하는 것 같습니다.


5

viewForKey:UITransitionContextToViewKeyios8에서 nil 을 반환합니다. 그래서 그것이 nil이면 'to'뷰 컨트롤러에서 뷰를 가져옵니다.

그러나 이로 인해 completeTransition:YES호출 될 때 'to'뷰가 컨테이너에서 창으로 이동되지 않는 것으로 보입니다 . 따라서 viewForKey:UITransitionContextToViewKeynil을 반환 하면으로 넘어 가서 toVC.viewnil을 반환했다는 사실을 추적하고 완료 후 컨테이너의 초기 수퍼 뷰 (윈도우)로 이동합니다.

이 코드 iOS7에의 작품뿐만 아니라 iOS8의 그래서, 그리고 해야 그들은 그것을 수정하거나 그렇지 않으면 너무도 iOS9에서 작동합니다.

- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext {
    // Get the 'from' and 'to' views/controllers.
    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    BOOL hasViewForKey = [transitionContext respondsToSelector:@selector(viewForKey:)]; // viewForKey is iOS8+.
    UIView *fromView = hasViewForKey ?
        [transitionContext viewForKey:UITransitionContextFromViewKey] :
        fromVC.view;
    UIView *toView = hasViewForKey ?
        [transitionContext viewForKey:UITransitionContextToViewKey] :
        toVC.view;

    // iOS8 has a bug where viewForKey:to is nil: http://stackoverflow.com/a/24589312/59198
    // The workaround is: A) get the 'toView' from 'toVC'; B) manually add the 'toView' to the container's
    // superview (eg the root window) after the completeTransition call.
    BOOL toViewNilBug = !toView;
    if (!toView) { // Workaround by getting it from the view.
        toView = toVC.view;
    }
    UIView *container = [transitionContext containerView];
    UIView *containerSuper = container.superview; // Used for the iOS8 bug workaround.

    // Perform the transition.
    toView.frame = container.bounds;
    [container insertSubview:toView belowSubview:fromView];
    [UIView animateWithDuration:kDuration delay:0 options:UIViewAnimationOptionCurveEaseIn animations:^{
        fromView.frame = CGRectOffset(container.bounds, 0, CGRectGetHeight(container.bounds));
    } completion:^(BOOL finished) {
        [transitionContext completeTransition:YES];

        if (toViewNilBug) {
            [containerSuper addSubview:toView];
        }
    }];
}

3

설정하면이 버그 (및 더 많은 것)가 사라진다는 것을 발견했습니다 modalPresentationStyle = UIModalPresentationFullScreen. 물론 사용자 정의 전환 애니메이션을 얻을 수 있습니다.


2

나도이 문제에 집착했다. 반투명 배경으로 사용자 정의 전환을 만들려고했는데, 여기에서 내가 왔던 뷰 컨트롤러를 볼 수 있지만 검정색 배경 만 얻었습니다. 이 스레드에서 Mark Aron의 답변이 도움이되었지만 Objective C로 작성되었으므로 iOS 9 및 iOS 10에 대해 테스트 한 해당 답변의 Swift 3 버전이 있습니다.

  1. UIPresentationController의 하위 클래스를 만듭니다. 다음과 같이 shouldRemovePresentersView를 false로 재정의합니다.

    class ModalPresentationController: UIPresentationController {
    
    override var shouldRemovePresentersView: Bool {
    return false
    }
    
    override func containerViewWillLayoutSubviews() {
    presentedView?.frame = frameOfPresentedViewInContainerView
    }
    }
  2. 새 뷰 컨트롤러를 인스턴스화하고 전환 대리자를 설정하는 위치에서 다음과 같이 사용자 지정 모달 프레젠테이션 스타일을 표시 할 것임을 나타냅니다.

    let newVC = mainStoryboard.instantiateViewController(withIdentifier: "newVC") as! NewViewController 
    
    newVC.transitioningDelegate = self
    
    newVC.modalPresentationStyle = UIModalPresentationStyle.custom
    
    newVC.modalPresentationCapturesStatusBarAppearance = true //optional
    
    present(newVC, animated: true, completion: nil)
  3. 이제 UIViewControllerTransitioningDelegate의 presentationController 메서드를 재정의하고 사용자 지정 UIPresentationController를 반환합니다. 나는 현재 수업의 확장으로 내 것을 가지고 있었다.

    extension CurrentViewController: UIViewControllerTransitioningDelegate {
    
    //this is where you implement animationController(forPresented) and animationController(forDismissed) methods
    
    func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
    
    return ModalPresentationController(presentedViewController: presented, presenting: source)
    
    }
    }

주목해야 할 또 다른 사항은 presentAnimator 클래스에서 fromView를 참조하지 않아야한다는 것입니다. 이것은 nil이고 런타임에 오류가 발생합니다. 그 외에 같은 것을 구현하면 애니메이션과 반투명 배경으로 사용자 정의 전환을 얻을 수 있습니다.


이 iis는 Swift 3에서 사용자 지정 모달 프레젠테이션을 수행하는 좋은 예입니다! 감사합니다 @gwinyai! presentationController(forPresented presented UIViewController,... 이전 swift API가 컴파일러를 화나게하지 않았지만 호출되지 않았기 때문에 새로운 swift 3 API를 보여주는 예제를 찾을 때까지 저는 이것에 대해 매우 고집했습니다 .
Natalia

2

이 문제를 만난 후 얼마 전에 잘 작동하는 거의 동일한 내용을 작성했기 때문에 매우 혼란 스러웠습니다. 꽤 엉망인 것처럼 보이고 근본 원인을 이해하지 못하는 것 같은 수정 사항을 찾기 위해 답변을 찾고 있습니다. 실제로 수정하기가 매우 쉽습니다.

어떤 대답이 변화는 말할 modalPresentationStyle.overFullScreen. 이것은 정확하고 .overCurrentContext작동합니다. 이것은 예상되는 동작이며 Apple 문서의 동작입니다. 그러나 이것이 모든 사람에게 효과가없는 이유는 무엇입니까? 왜 모든 해키 코드와 이것과 다른 것의 조합, 그리고 당신이해서는 안되는 미친 짓을 하는가?

보기가로드되기 전에 프레젠테이션 스타일을 설정해야합니다 . 이후가 아닙니다. init에서 수행하거나 이전 컨트롤러에서 수행하거나 원하는 방식으로 수행하십시오. 뷰가로드되기 전이라면 가능합니다.


1
나는에 프리젠 테이션 스타일을 설정 .overCurrentContext 합니다 (에서보기를로드하기 전에 init뷰 컨트롤러의)와 문제가 계속 발생
ricardopereira

1

새로운 UIModalPresentationOverCurrentContext를 사용하면 문제가 해결되었습니다. iOS 7의 원래 전환은 모달 아래에 뷰의 배경이 흐려지는 것이 었습니다.


어떤 이유로, 이것은 UIModalPresentationCurrentContext가 iOS 7에서했던 아래 뷰와의 상호 작용을 허용하지 않는 것 같습니다. 어떤 생각?
Christopher Wirt 2015 년

iOS 10에서 .overCurrentContext로 인해이 버그가 발생하지만 .fullscreen은 그렇지 않습니다. .overCurrentContext 사용에 대한 수정을 기대하고 왔지만 지금까지 UIPresentationController를 서브 클래 싱하는 것을 제외하고는 iOS 10에서 작동하는 것처럼 보이지 않습니다 ...
Natalia

0

좋아요, 여러분, iOS 13 이상에서 앱을 빌드 할 때 '작동하는 애니메이터'가 제대로 작동하지 않는 경우를 해결했다고 생각합니다.

Env Xcode 11.1, iOS 13.1

문제

내가 원하는 것은 매우 간단합니다. 컬렉션보기가 있는데 셀을 탭하면 세부보기로 이동합니다. 지루한 기본 스타일 인 'present modally'를 사용하는 대신 좀 더 재미있게 만들고 싶기 때문에 뷰 컨트롤러 전환을위한 애니메이터를 작성했습니다.

내 컬렉션 VC에서 세부 VC로 드래그 앤 드롭하여 IB에서 segue를 설정했습니다. segue의 스타일은 '모달로 프레젠테이션'이고 프레젠테이션은 '전체 화면'으로 설정됩니다.

자세히보기가 표시되면 모든 것이 예상대로 작동합니다. 하지만 디테일 뷰를 닫고 컬렉션 뷰로 돌아 가면 애니메이션 디테일 뷰만 볼 수 있고 컬렉션 뷰는 사라집니다. 여기 저기 찌르고 몇 가지 발견이 있습니다

1. 'animateTransition ()'함수에서 다음 줄이 호출 된 직후 컬렉션보기가 다시 시작되고 표시됩니다.

transitionContext.completeTransition(true)

2. 상세보기가 컬렉션보기를 완전히 덮지 않는 한, 컬렉션보기가 세부보기에서 뒤로 돌아갈 때 사라지지 않습니다.

해결책

솔직히 말해서 애니메이션 전환이 어떻게 작동하는지 거의 알지 못합니다. 따라서이 게시물과 다른 게시물 만 따라갈 수 있으며 각 답변을 시도해보십시오. 불행히도 그들 중 어느 것도 나를 위해 일하지 않습니다. 마지막으로, 제가 조정할 수있는 유일한 점은 IB에서 segue의 프레젠테이션 스타일입니다 (아주 처음에 했어야했던). 프레젠테이션을 'Over Full Screen'으로 설정하면 기적이 일어나고 문제가 해결됩니다. 디테일 뷰는 애니메이션과 함께 전체 화면으로 표시 될 수 있으며 닫히면 컬렉션 뷰를 배경으로 볼 수 있고 애니메이션 디테일 뷰를 볼 수 있습니다.

그런 다음 길을 따라 하나 더 발견

3. 'toView'및 'fromView'를 참조하려면 다음 두 방법이 모두 작동합니다.

간접적으로 :

transitionContext.viewController(forKey: .to)?.view
transitionContext.viewController(forKey: .from)?.view

직접 방법 :

transitionContext.view(forKey: .to)
transitionContext.view(forKey: .from)

그러나 segue 스타일을 'Over Full Screen'으로 전환했을 때 'toView'와 'fromView'모두에 대해 'nil'을 직접 반환하고 간접적으로 만 작동하는 방식으로이 문제는 다른 게시물 에서도 언급 되었으므로 가치가 있다고 생각합니다. 여기에 내 작은 발견을 게시합니다.

이것이 앞으로 누군가에게 도움이되기를 바랍니다.


0

콘텐츠보기 컨트롤러를 닫을 때 동일한 문제가 발생했습니다.

내 앱에는 하위 뷰 컨트롤러 (vc 표시)를 모달로 표시하는이 상위 뷰 컨트롤러가 있습니다. 그런 다음 childVC의 하위 뷰를 탭하면 다른 vc가 표시됩니다 (콘텐츠 뷰 컨트롤러 (vc 표시)라고 함).

내 문제는 ContentVC를 해제 할 때 (현재 제시중인 VC) 자식 VC (현재 제시된 VC)로 이동해야하지만 사용자 지정 전환이 완료 되 자마자 childVC가 갑자기 사라지고 부모 VC가 표시된다는 것입니다.

이 문제를 해결하기 위해 내가 한 것은

  1. 변경 .modalPresentationStylechildVC의 기본에서 parentVC 제시 .automatic.fullscreen .
  2. 그런 다음 .modalPresentationStylecontentVC도 변경했습니다 .fullscreen.

이것은 문제를 해결합니다. 그러나 부모 VC 위에 카드 스타일 시트로 자녀 VC를 표시하지 않습니다 (사용할 때.overCurrentContext iOS 13의 새로운 또는 자동) .

부모가 제시 할 때 childVC에 대한 카드 스타일 시트를 유지할 솔루션이 있는지 알고 싶습니다.


-3

뷰 컨트롤러를 다른 뷰 컨트롤러의 자식으로 추가합니다.

[self addChildViewController:childViewController];                 

확인하고 알려주세요.


난 이해가 안 돼요, 코딩을 사용해서 설명 할 수 있나요?
NiravPatel 2014-06-21


이것은 결코 질문에 답하지 않습니다. ChildViewController는 사용자 지정 전환에 관여하지 않으며 완전히 다른 주제입니다.
Andras M.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.