“From View Controller” biến mất khi sử dụng UIViewControllerContextTransitioning


105

Tôi có một vấn đề và tôi đã mô tả nó bên dưới.

Tôi đang sử dụng UIViewControllerContextTransitioningcho các chuyển đổi tùy chỉnh.

Tôi có 2 bộ điều khiển chế độ xem, bộ điều khiển chế độ xem thứ nhất và bộ điều khiển chế độ xem thứ hai.

Bây giờ tôi muốn thêm bộ điều khiển chế độ xem thứ hai trên bộ điều khiển chế độ xem thứ nhất với một hình ảnh động. Tôi đã đạt được nó, bây giờ bộ điều khiển chế độ xem thứ hai trong suốt, vì vậy chúng ta có thể thấy bộ điều khiển chế độ xem thứ nhất bên dưới bộ điều khiển chế độ xem thứ hai.

Nhưng tôi không thể nhìn thấy bộ điều khiển chế độ xem thứ nhất và tôi chỉ có thể thấy màn hình đen bên dưới bộ điều khiển chế độ xem thứ hai.

-(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];
    }];
}

Khi [self.transitionContext completeTransition:YES];được gọi, đột nhiên bộ điều khiển chế độ xem thứ nhất biến mất và màn hình đen hiển thị bên dưới bộ điều khiển chế độ xem thứ hai.

Có ai có ý tưởng? Cảm ơn.

Câu trả lời:


98

Tôi đang gặp vấn đề tương tự ở đây - có vẻ như một lỗi trong iOS 8. Tôi đã gửi một radar .

Tôi đã sử dụng Reveal để kiểm tra phân cấp chế độ xem sau khi màn hình chuyển sang màu đen. Chìa khóa UIWindowhoàn toàn trống - không có phân cấp chế độ xem nào cả!

Reveal'd

Tôi đã chơi xung quanh một chút và có vẻ như có một giải pháp dễ dàng, cho các trường hợp đơn giản. Bạn chỉ có thể thêm lại toViewControllerchế độ xem của làm chế độ xem phụ của cửa sổ chính:

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

Tôi đã kiểm tra và cửa sổ khóa rootViewControllervẫn được đặt chính xác, vì vậy điều đó tốt. Tôi không chắc điều gì sẽ xảy ra nếu bạn trình bày bộ điều khiển của mình từ bên trong bộ điều khiển phương thức đã được trình bày, vì vậy đối với các trường hợp phức tạp hơn, bạn sẽ phải thử nghiệm xung quanh.


2
Tôi cũng đã thấy vấn đề này. iOS 8 giới thiệu một phương pháp và các khóa mới để truy cập fromView và toView (Lưu ý: không phải bộ điều khiển chế độ xem) Có vẻ như các tham chiếu này không bị mất trong quá trình chuyển đổi. Bạn có thể thêm chúng vào dạng xem vùng chứa như bình thường nếu bạn vừa truy xuất chúng từ bộ điều khiển dạng xem.
tapi

1
Tôi đã thấy sự kỳ lạ tương tự trên iOS 8 khi cố gắng thêm lượt xem phụ vào chế độ xem của bộ điều khiển điều hướng của mình, trong viewDidLoad. Thêm lại chế độ xem của navigationController vào keyWindow dường như đã thành công, cảm ơn rất nhiều, Ash!
taber

1
Tôi vẫn thấy điều này trong GM (và bản sửa lỗi này vẫn hoạt động). Những người khác có nhìn thấy như vậy không? Đây chỉ là một thay đổi trong API?
rjkaplan

21
Tôi thấy rằng lỗi này (và nhiều lỗi khác!) Sẽ biến mất nếu bạn thiết lập modalPresentationStyle = UIModalPresentationFullScreen. Tất nhiên bạn vẫn nhận được hoạt ảnh chuyển tiếp tùy chỉnh của mình.
Chris

1
Cảm ơn @AshFurrow. Cách giải quyết tốt cho đến khi nó được sửa!
kandelvijaya

78

Tôi cảm thấy lý do đằng sau điều này nên được giải thích tốt hơn.

Chế độ xem biến mất vì bạn lấy chế độ xem của bộ điều khiển chế độ xem trình bày ra khỏi vị trí ban đầu của nó (hệ thống phân cấp chế độ xem), đặt nó vào bên trong containerView mà trình tạo hoạt ảnh của bạn cung cấp nhưng không bao giờ trả lại sau khi hoạt ảnh kết thúc. Vì vậy, khung nhìn của bộ điều khiển chế độ xem đó bị loại bỏ hoàn toàn với chế độ xem siêu cấp (containerView) khỏi cửa sổ hoàn toàn.

Trong iOS 7, hệ thống luôn trả lại các khung nhìn của bộ điều khiển chế độ xem có liên quan đến bản trình bày (trình bày và trình bày) về vị trí ban đầu của chúng sau khi quá trình chuyển đổi kết thúc tự động hoạt ảnh. Điều đó không còn xảy ra đối với một số kiểu trình bày trong iOS 8.

Quy tắc rất đơn giản: trình tạo hoạt ảnh chỉ nên thao tác chế độ xem của bộ điều khiển chế độ xem trình bày nếu chế độ xem của bộ điều khiển chế độ xem đó sẽ bị ẩn (bị xóa khỏi hệ thống phân cấp chế độ xem) hoàn toàn vào cuối quá trình chuyển đổi . Nói cách khác, điều đó có nghĩa là sau khi hoạt ảnh trình bày ban đầu kết thúc, chỉ khung nhìn của bộ điều khiển chế độ xem được trình bày sẽ được hiển thị chứ không phải chế độ xem của bộ điều khiển chế độ xem trình bày. Ví dụ: nếu bạn đặt độ mờ của chế độ xem được trình bày thành 50% và sử dụng UIModalPresentationFullScreen, bạn sẽ không thể thấy chế độ xem của bộ điều khiển chế độ xem bên dưới trình bày nhưng nếu bạn sử dụng UIModalPresentationOverFullscreen - bạn sẽ làm được ( shouldRemovePresentersViewphương thức của UIPresentationController chịu trách nhiệm chỉ định điều đó).

Tại sao không cho phép trình hoạt họa thao tác với chế độ xem của trình điều khiển chế độ xem trình bày mọi lúc? Trước hết, nếu chế độ xem của bộ điều khiển chế độ xem bản trình bày sẽ tiếp tục hiển thị sau khi hoạt ảnh kết thúc trong toàn bộ vòng đời của bản trình bày thì không cần phải tạo hoạt ảnh cho nó - nó chỉ giữ nguyên vị trí của nó. Thứ hai, nếu quyền sở hữu đối với bộ điều khiển chế độ xem đó được chuyển sang bộ điều khiển bản trình bày, bộ điều khiển bản trình bày rất có thể sẽ không biết cách bố trí chế độ xem của bộ điều khiển chế độ xem đó khi cần, chẳng hạn như khi hướng thay đổi, nhưng chủ sở hữu ban đầu của bộ điều khiển chế độ xem trình bày thì không. .

Trong iOS 8, viewForKey:phương pháp đã được giới thiệu để lấy các khung nhìn mà trình tạo hoạt ảnh thao tác. Đầu tiên, nó hữu ích để tuân theo quy tắc được mô tả ở trên bằng cách trả về nil bất cứ khi nào người tạo hoạt ảnh không được chạm vào chế độ xem. Thứ hai, nó có thể trả về một chế độ xem khác để trình tạo hoạt ảnh. Hãy tưởng tượng rằng bạn đang triển khai một bản trình bày tương tự như biểu mẫu. Trong trường hợp này, bạn muốn thêm một số bóng hoặc trang trí xung quanh khung nhìn của bộ điều khiển chế độ xem được trình bày. Người làm hoạt hình sẽ tạo hoạt ảnh trang trí đó thay vào đó và chế độ xem của bộ điều khiển chế độ xem được trình bày sẽ là con của trang trí.

viewControllerForKey: không biến mất, nó vẫn có thể được sử dụng nếu cần truy cập trực tiếp vào bộ điều khiển chế độ xem nhưng trình tạo hoạt ảnh không nên đưa ra bất kỳ giả định nào về các chế độ xem mà nó cần để tạo hoạt ảnh.

Có một số điều bạn có thể làm để khắc phục sự cố một cách chính xác với chế độ xem của trình điều khiển chế độ xem trình bày biến mất khi bạn đặt rõ ràng nó bên trong chế độ xem vùng chứa của trình tạo hoạt ảnh:

  1. Nếu không cần tạo hiệu ứng cho khung nhìn của bộ điều khiển chế độ xem trình bày, hãy sử dụng viewForKey:để lấy các chế độ xem để tạo hiệu ứng thay vì tiếp cận để xem trực tiếp các chế độ xem của bộ điều khiển. viewForKey:có thể trả về con số không hoặc thậm chí là các quan điểm hoàn toàn khác.

  2. Nếu bạn muốn tạo hiệu ứng cho khung nhìn của bộ điều khiển chế độ xem trình bày, bạn nên cân nhắc sử dụng UIModalPresentationFullScreenstyle hoặc tiếp tục sử dụng UIModalPresentationCustomvà triển khai lớp con của riêng bạn của UIPresentationController với shouldRemovePresentersViewtrả về YES. Trên thực tế, việc triển khai phương pháp này là sự khác biệt chính giữa các bộ điều khiển bản trình bày nội bộ được xác định bởi UIModalPresentationFullScreenUIModalPresentationCustomkiểu ngoài thực tế là phương pháp sau cho phép bạn sử dụng bộ điều khiển bản trình bày tùy chỉnh.

  3. Trong tất cả các trường hợp hiếm hoi khác, bạn sẽ phải trả chế độ xem của trình điều khiển chế độ xem trình bày về vị trí ban đầu của nó như các câu trả lời khác được đề xuất.


2
Điều đó thật kỳ lạ vì mã này chỉ dựa vào viewControllerForKey:'s viewkhi viewForKey:trả về nil và tôi vẫn phải thêm lại nó vào cửa sổ theo cách thủ công. Bạn có ví dụ về mã hoạt động mà không có giải pháp này không?
Ash Furrow

Chà, nếu viewForKey:trả về nil thì chắc chắn bạn sẽ phải thêm lại chế độ xem của bộ điều khiển chế độ xem trình bày vào cửa sổ nếu bạn xóa nó khỏi nó trong trình hoạt họa của mình. Trong trường hợp viewForKey trả về chế độ xem của bộ điều khiển chế độ xem thực tế, có thể an toàn để di chuyển chế độ xem đó vì UIKit sẽ di chuyển nó về vị trí ban đầu sau khi vòng đời bản trình bày kết thúc.
egdmitry

Cảm ơn bạn đã giải thích lý do đằng sau vấn đề này. Bạn hoàn toàn đúng. Di chuyển vị trí của chế độ xem trong hệ thống phân cấp chế độ xem mà không thay thế nó rõ ràng sẽ khiến nó biến mất (đăng iOS 8 và tôi đang làm việc với iOS 10 ngay bây giờ!) Cảm ơn bạn đã làm rõ.
Clay Ellis

1
Cảm ơn egdmitry cho sự làm rõ của bạn. Mà nâng một câu hỏi đó là: làm thế nào để bạn nghĩ rằng tôi nên thực hiện một tiết lộ như trình bày? Một trong những trường hợp rất phổ biến hiện nay khi mà dạng xem trình bày trình chiếu một phần ra ngoài để hiển thị dạng xem được trình bày bên dưới? Trong trường hợp này, cả chế độ xem trình bày và đã trình bày đều cần phải ở trên màn hình và chế độ xem trình bày là một hoạt ảnh.
Andrea

70

Trong iOS 8, bạn phải thao tác các chế độ xem được trả về viewForKey:thay vì thuộc .viewtính của bộ điều khiển chế độ xem được trả về viewControllerForKey:. Điều này không đặc biệt rõ ràng từ tài liệu beta, nhưng nếu bạn xem xét nguồn của UIViewControllerTransitioning.h, bạn sẽ thấy nhận xét này ở trên 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;

Vì vậy, thay vì điều chỉnh khung, v.v. của toViewController.view, hãy sử dụng giá trị trả về của [transitionContext viewForKey:UITransitionContextToViewKey].

Nếu ứng dụng của bạn cần hỗ trợ iOS7 và / hoặc Xcode 5, thì bạn có thể sử dụng phương pháp danh mục đơn giản trên UIViewController như sau:

- (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
}

Sau đó, lấy của bạn toViewControllerfromViewControllernhư bình thường, nhưng nhận các lượt xem bằng cách sử dụng [toViewController viewForTransitionContext:transitionContext].

Chỉnh sửa: Có vẻ như có một lỗi, trong đó chế độ xem của bộ điều khiển chế độ xem trình bày là 0 khi được trả về viewForKey, điều này ngăn bạn thực hiện các chuyển đổi phương thức làm sinh động chế độ xem trình bày (chẳng hạn như trượt ra hoặc lật ngang). Tôi đã gửi một lỗi cho iOS8 tại rdar: // 17961976 ( http://openradar.appspot.com/radar?id=5210815787433984 ). Cũng xem dự án mẫu tại http://github.com/bcherry/TransitionBug

Chỉnh sửa 2: Cảm ơn sỏi về đề xuất, việc sử dụng UIModalPresentationFullScreen sẽ khắc phục được sự cố. Có lẽ đây không phải là một lỗi. Apple có thể dự định rằng UIModalPresentationCustom chỉ sửa đổi chế độ xem của phương thức đến. Nếu bạn muốn sửa đổi dạng xem đi, bạn cần đảm bảo trình bày toàn màn hình của dạng xem mới? Trong mọi trường hợp, bạn nên sử dụng viewForKeyvà UIModalPresentationFullScreen.


2
Lỗi viewForKey đã khiến tôi phát điên! - cảm ơn bạn đã gửi. FWIW quá trình chuyển đổi của tôi đang hoạt động tốt khi nhận được chế độ xem từ UITransitionContextToViewControllerKey, nhưng quá trình chuyển đổi của tôi chỉ áp dụng một biến đổi cho toàn bộ chế độ xem. Tôi không chắc liệu điều đó có nên được hiểu là manipulatinglượt xem của các VC hay không ...
MathewS

1
Chà - thật là dở hơi. Tôi không thấy điều đó trong các khác biệt - có lẽ vì đó chỉ là một số nhận xét nhỏ. Thực sự khó chịu khi Apple kéo một diễn viên đóng thế như thế này. Ngón tay lướt qua radar của bạn.
Ash Furrow,

Tôi cũng thấy viewForKeylỗi trong GM. Những người khác cũng vậy? Bạn đã tìm ra cách giải quyết hợp lý cho nó chưa?
rjkaplan

2
Tôi nghĩ theo nhận xét của - viewForKey// viewForKey: có thể trả về nil , điều này cho thấy rằng trình tạo hoạt ảnh không nên thao tác chế độ xem của bộ điều khiển chế độ xem được liên kết. Trả lại nilkhông phải là một lỗi.
Ken Kuan

4
@kenKuan bạn có thể đúng. khi sử dụng UIModalPresentationFullScreen, viewForKeytrả về chế độ xem từ và chế độ xem. Vì vậy, có thể nó cố ý trả về nil cho UIModalPresentationCustom. Tôi đang cập nhật báo cáo lỗi của mình và sẽ đăng lại tại đây nếu tôi nhận được phản hồi từ Apple về nó.
bcherry

24

Việc không đặt modalPresentationStylethành UIModalPresentationCustom đã khắc phục sự cố cho tôi.

Nói cách khác, việc để mặc định UIModalPresentationFullScreen thay vì chỉ định UIModalPresentationCustom đã khắc phục sự cố chế độ xem biến mất. Lưu ý rằng giao thức UIViewControllerTransitioningDelegate dường như vẫn được tuân thủ ngay cả khi để điều này ở chế độ mặc định. Nếu tôi nhớ chính xác, đã có lúc UIModalPresentationCustom là một yêu cầu.

Hoạt động cho đến nay, đã chỉ thử điều này cho các hoạt ảnh không tương tác.


1
ồ. Điều đó đã làm được! Tôi đã thử nghiệm mà không có modalPresentationStyle trong iOS7 & 8 và nó hoạt động ở cả hai. Cảm ơn!!
Ah Ryun Moon

1
Cảm ơn bạn! Điều này kết hợp với sử dụng viewForKey:thay vì .viewtrên các viewControllerForKey:bản sửa lỗi khắc phục tất cả các vấn đề cho tôi.
bcherry

1
Điều này đã khắc phục sự cố cho tôi khi không sử dụng viewForKey, nhưng tôi cho rằng điều đó cũng nên được sử dụng.
Kevin Sliech

5
Mặc dù điều này dường như khắc phục được sự cố, nhưng điều quan trọng cần lưu ý là màn hình phía sau bộ điều khiển chế độ xem của bạn sẽ trở thành màu đen khi nó được hiển thị. Điều này rất quan trọng nếu bộ điều khiển chế độ xem của bạn không ở chế độ toàn màn hình.
The dude

16

Tôi đã tìm thấy câu trả lời cực kỳ hữu ích này trong một chủ đề liên quan của Lefteris: https://stackoverflow.com/a/27165723/3709173

Tóm lại:

  1. đặt modalPresentationStyle thành .Custom
  2. lớp con UIPresentationController, ghi đè shouldRemovePresentersView (với KHÔNG)
  3. ghi đè bản trình bàyControllerForPresentedViewController trong lớp TransitionDelegate của bạn và trả về UIPresentationController tùy chỉnh của bạn

+1 trong chuyển đổi tùy chỉnh của bạn, không thêm toView khi hoạt ảnh loại bỏ đang diễn ra.

Minh chứng ở đây:

https://www.dropbox.com/s/7rpkyamv9k9j18v/CustomModalTransition.zip?dl=0 mà không có bất kỳ hack nào! nó giống như phép thuật! :)


1
Đây là câu trả lời đúng thực tế. Mà không có trò ảo thuật như trong một trong những được chấp nhận. Cảm ơn, Mark!
Andrei Malygin,

Thật không may, điều này không hoạt động trong iOS 12.4, Xcode 10.3. Màn hình chuyển sang màu đen sau khi Hoàn thành quá trình chuyển đổi (tất cả các quan điểm đã được loại bỏ khỏi hệ thống phân cấp Tuy nhiên, thiết lập tài sản 'modalPresentationStyle' thành '.fullscreen' NÀO Cheers làm việc...
Womble

Tôi đã thử phiên bản obj-C từ việc triển khai Swift của Mark và gwinyai trong dự án của mình. Thật không may, không ai trong số họ đang hoạt động như mong đợi. Tôi đang sử dụng Xcode 11.1 và mục tiêu xây dựng là iOS 13.0, tôi đã thử trên cả thiết bị và trình mô phỏng. Trong trường hợp của tôi, thiết lập cơ bản của tôi là chế độ xem bộ sưu tập và khi bạn nhấn vào một ô, nó sẽ chuyển sang chế độ xem chi tiết với hoạt ảnh. Tuy nhiên, nó hoạt động hoàn toàn tốt nếu tôi đang sử dụng hoạt ảnh chuyển tiếp mặc định. VC trình bày sẽ không biến mất khi tôi tiếp tục từ chế độ xem chi tiết.
infinity_coding7

8

Trong iOS 8, bạn cần tạo một UIPresentationController và triển khai phương pháp bên dưới, trong UIViewControllerTransitioningDelegate.

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

Yêu cầu người được ủy quyền của bạn để sử dụng bộ điều khiển bản trình bày tùy chỉnh để quản lý cấu trúc phân cấp dạng xem khi trình bày bộ điều khiển dạng xem.

Giá trị trả lại:

Bộ điều khiển bản trình bày tùy chỉnh để quản lý bản trình bày theo phương thức.

Thảo luận:

Khi bạn trình bày bộ điều khiển dạng xem bằng kiểu trình bày UIModalPresentationCustom, hệ thống sẽ gọi phương thức này và yêu cầu bộ điều khiển bản trình bày quản lý kiểu tùy chỉnh của bạn. Nếu bạn triển khai phương pháp này, hãy sử dụng nó để tạo và trả về đối tượng bộ điều khiển bản trình bày tùy chỉnh mà bạn muốn sử dụng để quản lý quá trình trình bày.

Nếu bạn không triển khai phương pháp này hoặc nếu việc triển khai phương pháp này của bạn trả về nil, hệ thống sử dụng đối tượng trình điều khiển bản trình bày mặc định. Bộ điều khiển bản trình bày mặc định không thêm bất kỳ dạng xem hoặc nội dung nào vào hệ thống phân cấp dạng xem.

Tính khả dụng Có sẵn trong iOS 8.0 trở lên.

Để biết thêm thông tin, hãy xem video WWDC 2014:

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

Ngoài ra còn có một mã mẫu từ WWDC có tên "LookInside: Trình điều khiển Trình điều khiển Thích ứng và Đối tượng Hoạt hình Tùy chỉnh", bạn có thể tải xuống từ trang mã mẫu WWDC 2014.

Bạn có thể cần thay đổi mã mẫu một chút. Phương thức init UIPresentationController đã thay đổi thành:

initWithPresentedViewController:presented presentingViewController:presenting

Trước khi nó được trình bày và sau đó được trình bày. Chỉ cần hoán đổi chúng và nó sẽ hoạt động.


Xin lỗi vì không xem video được liên kết, nhưng tôi không nghĩ bạn cần một UIPresentationController tùy chỉnh trừ khi bạn muốn một bản trình bày không chuẩn sau khi hoạt ảnh hoàn thành, như một dạng xem được trình bày hình tròn. Nếu bạn chỉ muốn một hoạt ảnh khác, việc triển khai UIViewControllerAnimatedTransitioning là đủ, dựa trên kiến ​​thức hạn chế của tôi.
Vaddadi Kartick

7

thay vì [inView insertSubview: toViewController.view aboveSubview: fromViewController.view]; chỉ cần thêm: [inView addSubview: toViewController.view];

if (self.presenting) {

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

} else {
    // your code
}

Bạn có thể xem một ví dụ ở đây: liên kết và nó hoạt động trên iOS 7 và iOS 8


Đây sẽ là câu trả lời được chấp nhận để thực hiện kiểu hoạt ảnh UIModalPresentationStyleCustom vì không cần thêm fromViewController vào containerView. Bạn chỉ cần thêm toViewController trong khi trình bày hoạt ảnh.
Scott Kaiser

Điều này rất hữu ích, thực sự
Dmitry Bondarev

7

Đây là phiên bản Objective C của bản sửa lỗi của Ash.

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

Tôi đã phải hoán đổi thứ tự và gọi phương thức [transferContext completeTransition:] sau khi thêm lại chế độ xem vào để trình bày bộ điều khiển chế độ xem mới từ khối hoàn thành loại bỏ của bộ điều khiển chế độ xem khác hoạt động bình thường.

Tôi không biết rằng điều này sẽ sửa chữa nó cho mọi người nhưng nó hoạt động trong ứng dụng của tôi. Chúc mừng!


5

Tôi thấy điều này hoạt động tốt đối với obj-C:

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

Có vẻ hoạt động tốt trên cả ios7 và ios8.


5

Tôi thấy rằng viewForKey:UITransitionContextToViewKeytrả về nil trên ios8. Vì vậy, nếu đó là số không, tôi lấy chế độ xem từ bộ điều khiển chế độ xem 'sang'.

Tuy nhiên, điều này dường như dẫn đến chế độ xem 'tới' không được chuyển từ vùng chứa sang cửa sổ khi completeTransition:YESđược gọi. Vì vậy, nếu viewForKey:UITransitionContextToViewKeytrả về nil, tôi rơi vào toVC.viewvà theo dõi thực tế là nó đã trả về nil, và sau khi hoàn thành, tôi chuyển nó sang superview ban đầu của vùng chứa (tình cờ là cửa sổ).

Vì vậy, mã này hoạt động trên iOS7 cũng như iOS8 và cũng sẽ hoạt động trên iOS9 ngay cả khi họ sửa nó hay không.

- (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

Tôi thấy rằng lỗi này (và nhiều lỗi khác!) Sẽ biến mất nếu bạn thiết lập modalPresentationStyle = UIModalPresentationFullScreen. Tất nhiên bạn vẫn nhận được hoạt ảnh chuyển tiếp tùy chỉnh của mình.


2

Tôi cũng gặp khó khăn về vấn đề này. Tôi đang tìm cách tạo một chuyển đổi tùy chỉnh với nền bán trong suốt, nơi tôi vẫn có thể nhìn thấy bộ điều khiển chế độ xem mà tôi đang đến nhưng tôi chỉ nhận được nền đen. Tôi tìm thấy câu trả lời của Mark Aron trong chủ đề này đã giúp tôi nhưng nó được viết bằng Objective C nên đây là phiên bản Swift 3 của câu trả lời đó mà tôi đã thử nghiệm cho iOS 9 và iOS 10:

  1. Tạo một lớp con của UIPresentationController. Ghi đè shouldRemovePresentersView thành false như sau:

    class ModalPresentationController: UIPresentationController {
    
    override var shouldRemovePresentersView: Bool {
    return false
    }
    
    override func containerViewWillLayoutSubviews() {
    presentedView?.frame = frameOfPresentedViewInContainerView
    }
    }
  2. Tại nơi bạn đang khởi tạo bộ điều khiển dạng xem mới và đặt đại biểu chuyển tiếp của nó, hãy chỉ ra rằng bạn muốn nó hiển thị kiểu trình bày theo phương thức tùy chỉnh như sau:

    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. Bây giờ ghi đè phương thức PresentationController của UIViewControllerTransitioningDelegate và trả về UIPresentationController tùy chỉnh của bạn. Tôi đã có phần mở rộng của mình cho lớp học hiện tại của mình:

    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)
    
    }
    }

Một điều khác cần lưu ý là bạn không nên thử và tham chiếu fromView trong lớp presentAnimator của bạn. Điều này sẽ là không và bạn sẽ gặp lỗi khi chạy. Ngoài ra, nếu bạn triển khai những thứ như những thứ như vậy, bạn sẽ nhận được chuyển đổi tùy chỉnh của mình với hoạt ảnh của nó và nền bán trong suốt nếu bạn tạo.


Iis này là một ví dụ tuyệt vời để thực hiện một bản trình bày theo phương thức tùy chỉnh trong Swift 3! Cảm ơn @gwinyai! Tôi đã rất khó khăn về vấn đề này cho đến khi tôi tìm thấy một ví dụ cho thấy API swift 3 mới presentationController(forPresented presented UIViewController,... vì API swift trước đó không làm phiền trình biên dịch nhưng không được gọi.
Natalia

2

Sau khi gặp phải vấn đề này, tôi đã rất bối rối, bởi vì tôi đã viết một cái gì đó gần như giống hệt nhau cách đây không lâu và hoạt động tốt. Đến đây để tìm kiếm câu trả lời để tìm các bản sửa lỗi trông khá khó hiểu và dường như không hiểu nguyên nhân gốc rễ ... nó thực sự rất dễ sửa.

Một số câu trả lời đề cập đến việc thay đổi modalPresentationStylethành .overFullScreen. Điều này là chính xác, .overCurrentContextcũng sẽ hoạt động. Điều này được mong đợi, và các tài liệu về hành vi của Apple. Nhưng tại sao điều này không hiệu quả với tất cả mọi người? Tại sao tất cả các mã hacky, và sự kết hợp của cái này với cái khác, và những thứ điên rồ mà bạn không nên làm?

Hóa ra, bạn cần đặt phong cách trình bày TRƯỚC KHI TẢI XEM . Không phải sau khi. Làm điều đó trong init, hoặc làm điều đó từ bộ điều khiển trước đó hoặc bất kỳ cách nào bạn muốn - miễn là trước khi chế độ xem tải.


1
Tôi đặt kiểu bản trình bày thành .overCurrentContext trước khi tải chế độ xem (trong trình initđiều khiển chế độ xem) và sự cố vẫn xảy ra
ricardopereira

1

Sử dụng UIModalPresentationOverCurrentContext mới đã sửa lỗi cho tôi. Quá trình chuyển đổi ban đầu của tôi trên iOS 7 chỉ là làm mờ nền của chế độ xem bên dưới phương thức.


Vì một số lý do, điều này dường như không cho phép tương tác với chế độ xem bên dưới, nơi UIModalPresentationCurrentContext đã làm trong iOS 7. Bạn có suy nghĩ gì không?
Christopher Wirt

Rất tiếc đối với tôi trên iOS 10, .overCurrentContext dẫn đến lỗi này nhưng .fullscreen thì không. Tôi đến đây với hy vọng cho một sửa chữa cho việc sử dụng .overCurrentContext nhưng cho đến nay không có gì có vẻ như nó sẽ làm việc trong iOS 10 ngoại trừ có lẽ subclassing UIPresentationController ...
Natalia

0

Được rồi, các bạn, tôi nghĩ rằng tôi đã giải quyết được một trường hợp rằng 'trình tạo hoạt ảnh đang hoạt động' ngừng hoạt động bình thường khi bạn xây dựng ứng dụng trong iOS 13 trở lên.

Env Xcode 11.1, iOS 13.1

Vấn đề

Những gì tôi muốn làm rất đơn giản: Tôi có một chế độ xem bộ sưu tập, khi một ô được chạm vào, nó sẽ chuyển sang chế độ xem chi tiết. Thay vì sử dụng kiểu mặc định nhàm chán là 'hiện tại theo phương thức', tôi muốn làm cho nó thú vị hơn, vì vậy tôi đã viết một trình tạo hoạt ảnh cho quá trình chuyển đổi bộ điều khiển chế độ xem.

Tôi thiết lập segue trong IB bằng cách kéo và thả từ VC bộ sưu tập của tôi đến VC chi tiết. Kiểu của segue là 'Trình bày theo phương thức' và bản trình bày được đặt thành 'Toàn màn hình'.

Khi nó hiển thị chế độ xem chi tiết, mọi thứ hoạt động như mong đợi. Tuy nhiên, khi tôi loại bỏ chế độ xem chi tiết và quay lại chế độ xem bộ sưu tập, tôi chỉ có thể xem chế độ xem chi tiết hoạt hình, chế độ xem bộ sưu tập chỉ biến mất. Tôi đã chọc ở đây và ở đó và tôi có một số khám phá

1. Ngay sau khi dòng sau được gọi từ hàm 'animateTransition ()', chế độ xem bộ sưu tập tiếp tục và hiển thị

transitionContext.completeTransition(true)

2. Miễn là chế độ xem chi tiết không bao phủ hoàn toàn chế độ xem bộ sưu tập, chế độ xem bộ sưu tập sẽ không biến mất khi nó tách ra khỏi chế độ xem chi tiết

Giải pháp

Thành thật mà nói, tôi biết rất ít về cách hoạt động của quá trình chuyển đổi hoạt hình. Nên mình chỉ có thể theo dõi bài này bài kia , thử từng câu trả lời. Thật không may, không ai trong số họ làm việc cho tôi. Cuối cùng, tôi đã đi đến một điểm mà điều duy nhất tôi có thể điều chỉnh là phong cách trình bày của segue trong IB (điều mà tôi đáng lẽ phải làm ngay từ đầu). Khi tôi đặt bản trình bày thành 'Toàn màn hình', điều kỳ diệu sẽ xảy ra và vấn đề của tôi đã được giải quyết. Chế độ xem chi tiết có thể hiển thị toàn màn hình với hoạt ảnh và khi nó bị loại bỏ, tôi có thể thấy cả chế độ xem bộ sưu tập dưới dạng nền và chế độ xem chi tiết động.

Sau đó, một khám phá khác trên đường

3.Để tham chiếu đến 'toView' và 'fromView', cả hai phương pháp sau đều hoạt động

Cách gián tiếp:

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

Trực tiếp cách:

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

Nhưng khi tôi chuyển phong cách segue thành 'Toàn màn hình', cách trực tiếp trả về 'nil' cho cả 'toView' và 'fromView' và chỉ cách gián tiếp hoạt động, vấn đề này cũng được đề cập trong một bài đăng khác , vì vậy tôi nghĩ nó đáng để đăng khám phá nhỏ của tôi ở đây.

Hy vọng điều này sẽ hữu ích cho ai đó trong tương lai.


0

Tôi đã gặp sự cố tương tự khi loại bỏ bộ điều khiển chế độ xem nội dung.

Ứng dụng của tôi có bộ điều khiển chế độ xem gốc này hiển thị bộ điều khiển chế độ xem con (trình bày vc) theo phương thức. Sau đó, khi một chế độ xem phụ trong childVC được nhấn, nó sẽ hiển thị một vc khác (mà tôi đang gọi là bộ điều khiển chế độ xem nội dung (vc đã trình bày))

Vấn đề của tôi là, khi loại bỏ contentVC (bây giờ là vc trình bày), nó sẽ chuyển đến VC con (bây giờ là VC đã trình bày) nhưng ngay sau khi quá trình chuyển đổi tùy chỉnh của tôi kết thúc, childVC đột nhiên biến mất, hiển thị VC mẹ.

Những gì tôi đã làm để giải quyết vấn đề này là

  1. thay đổi .modalPresentationStylechildVC do cha mẹ hiển thị từ mặc định .automaticthành .fullscreen.
  2. Sau đó, cũng thay đổi nội dung .modalPresentationStylecủa contentVC .fullscreen.

Điều này giải quyết vấn đề. nhưng nó sẽ không hiển thị VC con của bạn dưới dạng trang kiểu thẻ trên đầu trang cha mẹ (khi sử dụng .overCurrentContexthoặc tự động), tính năng mới trong iOS 13.

Rất muốn biết nếu có bất kỳ giải pháp nào sẽ giữ lại tấm thẻ kiểu cho trẻ em khi được phụ huynh xuất trình.


-3

thêm bộ điều khiển chế độ xem dưới dạng con của bộ điều khiển chế độ xem khác.

[self addChildViewController:childViewController];                 

kiểm tra và cho tôi biết.


tôi không hiểu, bạn có thể mô tả nó bằng cách sử dụng mã hóa không?
NiravPatel


điều này không có cách nào trả lời câu hỏi. ChildViewControllers không tham gia vào bất kỳ phần nào của quá trình chuyển đổi tùy chỉnh, chúng là một chủ thể hoàn toàn khác.
Andras M.
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.