UIViewControllerContextTransitioning kullanılarak "Görünüm Denetleyicisinden" kayboluyor


105

Bir sorunum var ve bunu aşağıda açıkladım.

UIViewControllerContextTransitioningÖzel geçişler için kullanıyorum .

2 görünüm denetleyicim, birinci görünüm denetleyicim ve ikinci görünüm denetleyicim var.

Şimdi birinci görünüm denetleyicisine bir animasyonla ikinci görünüm denetleyicisi eklemek istiyorum. Bunu başardım, şimdi ikinci görüntü denetleyicisi şeffaf, böylece birinci görüntü denetleyicisini ikinci görüntü denetleyicisinin altında görebiliriz.

Ancak ilk görüntü denetleyicisini göremiyorum ve ikinci görüntü denetleyicisinin altında yalnızca siyah ekran görebiliyorum.

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

Ne zaman [self.transitionContext completeTransition:YES];denilen, aniden ilk görünüm denetleyicisi kaybolur ve ikinci görünüm denetleyicisi altında siyah ekran görüntülenir.

Herhangi birinin fikri var mı? Teşekkürler.

Yanıtlar:


98

Burada da aynı sorunu yaşıyordum - iOS 8'deki bir hataya benziyor . Bir radar kaydettim .

Ekran karardıktan sonra görünüm hiyerarşisini incelemek için Göster'i kullandım . Anahtar UIWindowtamamen boş - hiçbir görünüm hiyerarşisi yok!

Açığa çıktı

Biraz oynadım ve basit durumlar için kolay bir çözüm var gibi görünüyor. toViewControllerAna pencerenin alt görünümü olarak 'ın görünümünü yeniden ekleyebilirsiniz :

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

Kontrol ettim ve anahtar pencere rootViewControllerhala doğru ayarlanmış, yani sorun değil. Denetleyicinizi önceden sunulan bir modal denetleyiciden sunarsanız ne olur emin değilim, bu nedenle daha karmaşık durumlar için etrafta deneyler yapmanız gerekir.


2
Ben de bu konuyu gördüm. iOS 8, fromView ve toView'a erişmek için yeni bir yöntem ve anahtarlar sunar (Not: görünüm denetleyicisi değil) Geçiş sırasında bu referanslar kaybolmamış gibi görünür. Bunları, görünüm denetleyicilerinden yeni almış olsaydınız, normalde yaptığınız gibi kapsayıcı görünümüne ekleyebilirsiniz.
tapi

1
ViewDidLoad'da navigasyon denetleyicimin görünümüne alt görünümler eklemeye çalışırken benzer iOS 8 garipliği görüyordum. NavigationController'ın görünümünü keyWindow'a yeniden eklemek hile yaptı, çok teşekkürler Ash!
taber

1
Bunu hala GM'de görüyorum (ve bu düzeltme hala çalışıyor). Başkaları da aynı şeyi görüyor mu? Bu sadece API'deki bir değişiklik mi?
rjkaplan

21
Ayarladığınızda bu hatanın (ve çok daha fazlasının!) Ortadan kalktığını buldum modalPresentationStyle = UIModalPresentationFullScreen. Elbette hala özel geçiş animasyonunuzu alıyorsunuz.
Chris

1
Teşekkürler @AshFurrow. Düzeltilene kadar güzel bir çözüm!
kandelvijaya

78

Bunun arkasındaki gerekçenin daha iyi açıklanması gerektiğini düşünüyorum.

Görünüm, sunum görünümü denetleyicisinin görünümünü orijinal konumundan çıkardığınız için (görünüm hiyerarşisi), animatörünüzün sağladığı konteynerView'in içine koyduğunuz için kaybolur, ancak animasyon bittikten sonra onu asla geri döndürmez. Böylece denetleyicinin görünümü, denetleyicinin görünümü (containerView) ile pencereden tamamen kaldırılır.

İOS 7'de sistem, geçişin animasyonu otomatik olarak tamamlandıktan sonra, sunumda yer alan (sunan ve sunulan) görünüm denetleyicilerinin görünümlerini her zaman orijinal yerlerine döndürdü. Bu, iOS 8'deki bazı sunum stilleri için artık geçerli değil.

Kural çok basittir: animatör, yalnızca, bu görünüm denetleyicisinin görünümü geçişin sonunda tamamen gizlenecekse (görünüm hiyerarşisinden kaldırılacaksa) sunum yapan görünüm denetleyicisinin görünümünü değiştirmelidir . Başka bir deyişle, ilk sunum animasyonu bittikten sonra sadece sunulan görünüm denetleyicisinin görünümünün görünür olacağı ve sunum görünümü denetleyicisinin görünümü olmayacağı anlamına gelir. Örneğin, sunulan görünüm denetleyicisinin görünümünün opaklığını% 50'ye ayarlarsanız ve UIModalPresentationFullScreen'i kullanırsanız, sunulanın altında görünüm denetleyicisinin görünümünü göremezsiniz ancak UIModalPresentationOverFullscreen'i kullanırsanız - bunu shouldRemovePresentersViewbelirtmek için UIPresentationController'ın yöntemi sorumludur).

Animatörün sunum görünümü denetleyicisinin görüşünü her zaman değiştirmesine neden izin vermiyorsunuz? Her şeyden önce, sunum görünümü denetleyicisinin görünümü, tüm sunum yaşam döngüsü boyunca animasyon bittikten sonra görünür kalacaksa, onu canlandırmaya hiç gerek yoktur - sadece olduğu yerde kalır. İkincisi, bu görünüm denetleyicisinin sahipliği sunum denetleyicisine aktarılırsa, sunum denetleyicisi büyük olasılıkla, gerektiğinde örneğin yön değiştiğinde denetleyicinin görünümünü nasıl düzenleyeceğini bilemeyecek, ancak sunum görünümü denetleyicisinin asıl sahibi .

İOS 8'de viewForKey:, animatörün manipüle ettiği görünümleri elde etmek için yöntem tanıtıldı. İlk olarak, animatör görünüme dokunmaması gerektiğinde sıfıra dönerek yukarıda açıklanan kurala uymaya yardımcı olur. İkincisi, animatörün canlandırması için farklı bir görünüm döndürebilir . Form sayfasına benzer bir sunum uyguladığınızı hayal edin. Bu durumda, sunulan görünüm denetleyicisinin görünümünün etrafına biraz gölge veya dekorasyon eklemek istersiniz. Animatör bunun yerine bu dekorasyonu canlandıracak ve sunulan görünüm denetleyicisinin görünümü dekorasyonun bir çocuğu olacaktır.

viewControllerForKey: kaybolmaz, görünüm denetleyicilerine doğrudan erişim gerekiyorsa yine de kullanılabilir, ancak animatör canlandırması gereken görünümler hakkında herhangi bir varsayımda bulunmamalıdır.

Kaybolan sunum görünümü denetleyicisinin görünümüyle ilgili sorunu, onu animatörün kapsayıcı görünümüne açıkça yerleştirdiğinizde doğru şekilde düzeltmek için yapabileceğiniz birkaç şey vardır :

  1. Sunum görünümü denetleyicisinin görünümünü canlandırmanız gerekmiyorsa, viewForKey:denetleyicinin görünümlerini doğrudan görüntülemek için ulaşmak yerine görünümleri canlandırmak için kullanın. viewForKey:sıfır veya hatta tamamen farklı görünümler döndürebilir.

  2. Sunum görünümü denetleyicilerinin görünümüne animasyon uygulamak istiyorsanız, UIModalPresentationFullScreenstili kullanmayı düşünmeli veya döndürerek UIModalPresentationCustomkendi UIPresentationController alt sınıfınızı kullanmaya devam etmeli ve uygulamalısınız . Aslında, bu yöntemin uygulanması, özel sunum denetleyicileri kullanmanıza izin vermesi dışında stiller tarafından tanımlanan iç sunum denetleyicileri ve stiller arasındaki temel farktır .shouldRemovePresentersViewYESUIModalPresentationFullScreenUIModalPresentationCustom

  3. Diğer tüm nadir durumlarda, diğer yanıtların önerildiği gibi, sunum görünümü denetleyicisinin görünümünü orijinal konumuna geri döndürmeniz gerekecektir.


2
Bu çok garip çünkü bu kod sadece nil döndürdüğünde viewControllerForKey:'s' e dayanıyor ve yine de onu pencereye manuel olarak yeniden eklemek zorunda kaldım. Bu geçici çözüm olmadan çalışan bir kod örneğiniz var mı? viewviewForKey:
Kül Karık

Eğer viewForKey:sıfır döndürürse , o zaman kesinlikle, animatörünüzden kaldırırsanız, sunum görünümü denetleyicisinin görünümünü pencereye yeniden eklemeniz gerekecektir. ViewForKey'in gerçek görünüm denetleyicisinin görünümünü döndürmesi durumunda, bu görünümü taşımak güvenlidir çünkü UIKit, sunum yaşam döngüsü bittikten sonra onu orijinal konumuna geri getirecektir.
egdmitry

Bu sorunun arkasındaki gerekçeyi açıkladığınız için teşekkür ederiz. Kesinlikle haklısın. Görünümün yerini değiştirmeden görünüm hiyerarşisindeki konumunu taşımak, açıkça ortadan kalkmasına neden olur (iOS 8 sonrası ve şu anda iOS 10 ile çalışıyorum!) Açıkladığınız için teşekkürler.
Kil Ellis

1
Açıklamanız için teşekkürler egdmitry. Hangisi başka bir soruyu gündeme getiriyor: Gösterme benzeri bir sunumu nasıl uygulamalıyım ? Sunulan görüşün altta sunulan görüşü göstermek için kısmen dışarı kaydığı günümüzde çok yaygın olanlardan biri mi? Bu senaryoda hem sunum hem de sunulan görünümlerin ekranda olması gerekir ve sunum görünümü canlandırılan görünümdür.
Andrea

70

İOS 8'de, tarafından döndürülen görünüm denetleyicilerinin özelliği viewForKey:yerine tarafından döndürülen görünümleri düzenlemeniz gerekir . Bu, beta belgelerinde özellikle net değil, ancak UIViewControllerTransitioning.h için kaynağa bakarsanız, yukarıda şu yorumu göreceksiniz :.viewviewControllerForKey: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;

Bu nedenle, çerçeveleri vb. Ayarlamak yerine toViewController.view, dönüş değerini kullanın [transitionContext viewForKey:UITransitionContextToViewKey].

Uygulamanızın iOS7 ve / veya Xcode 5'i desteklemesi gerekiyorsa, UIViewController'da aşağıdaki gibi basit bir kategori yöntemi kullanabilirsiniz:

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

Ardından, toViewControllerve fromViewControllerher zamanki gibi alın, ancak kullanarak görünümleri alın [toViewController viewForTransitionContext:transitionContext].

Düzenleme: Sunum görünümü denetleyicisinin görünümünün geri döndüğünde sıfır olduğu bir hata var gibi görünüyor, bu da sunum görünümünü viewForKeycanlandıran mod geçişleri yapmanızı engelliyor (kayma veya yatay kaydırma gibi). Rdar: // 17961976 ( http://openradar.appspot.com/radar?id=5210815787433984 ) adresinde iOS8 için bir hata bildirdim . Ayrıca numune projeyi görmek http://github.com/bcherry/TransitionBug

Düzenleme 2: Öneri için graveley'e teşekkürler, UIModalPresentationFullScreen kullanılması sorunu düzeltir. Belki de bu bir hata değildir. Apple, UIModalPresentationCustom ürününün yalnızca gelen modelin görünümünü değiştirmesini isteyebilir. Giden görünümü değiştirmek istiyorsanız, yeni görünümün tam ekran sunumunu garanti etmeniz gerekiyor mu? Her durumda, viewForKeyUIModalPresentationFullScreen kullanmalısınız .


2
ViewForKey hatası beni deli ediyordu! - dosyaladığınız için teşekkürler. FWIW, UITransitionContextToViewControllerKey'den görünümü alarak geçişim iyi çalışıyor, ancak geçişim yalnızca tüm görünüme bir dönüşüm uyguluyor. Bunun manipulating
VC'lerin

1
Vay canına - bu çılgınlık. Bunu farklarda görmedim - muhtemelen sadece küçük bir yorum olduğu için. Apple böyle bir numara yaptığında gerçekten sinir bozucu. Parmaklar radarınız hakkında çaprazlama yaptı.
Kül Karık

viewForKeyGM'de de hatayı görüyorum . Başkaları da mı? Bunun için makul bir çözüm buldunuz mu?
rjkaplan

2
- viewForKey// viewForKey yorumuna göre düşündüm : animatörün ilişkili görünüm denetleyicisinin görünümünü değiştirmemesi gerektiğini gösteren nil dönebilir . Geri dönmek nilbir hata değildir.
Ken Kuan

4
@kenKuan haklı olabilirsin. UIModalPresentationFullScreen kullanılırken, viewForKeygörünümden ve görünümden döndürür. Yani belki de UIModalPresentationCustom için nil döndürmesi kasıtlıdır. Hata raporumu güncelliyorum ve Apple'dan bu konuda haber alırsam buraya tekrar göndereceğim.
bcherry

24

modalPresentationStyleUIModalPresentationCustom olarak ayarlanmaması sorunu benim için düzeltti.

Başka bir deyişle, UIModalPresentationCustom belirtmek yerine varsayılan olarak UIModalPresentationFullScreen'i bırakmak kaybolan görünüm sorununu düzeltti. UIViewControllerTransitioningDelegate protokolünün, bu varsayılan değerde bırakıldığında bile hala takip edildiğini unutmayın. Doğru hatırlıyorsam, bir zamanlar UIModalPresentationCustom bir gereklilikti.

Şimdiye kadar çalışıyor, bunu yalnızca etkileşimli olmayan animasyonlar için denedi.


1
vay. Başardı! İOS7 ve 8'de modalPresentationStyle olmadan test ettim ve her ikisinde de çalışıyor. Teşekkürler!!
Ah Ryun Moon

1
Teşekkür ederim! Bu kullanarak kombine viewForKey:yerine .viewüzerinde viewControllerForKey:benim için tüm sorunları düzeltmeleri.
bcherry

1
Bu, viewForKey kullanmadan benim için sorunu çözdü, ancak bunun da kullanılması gerektiğini düşünüyorum.
Kevin Sliech

5
Bu sorunu çözmüş gibi görünse de, görüntü denetleyicinizin arkasındaki ekranın görüntülendiğinde kararacağını unutmamak önemlidir. Görünüm denetleyiciniz tam ekran değilse bu önemlidir.
dostum

16

Bu son derece yararlı yanıtı Lefteris'in ilgili bir ileti dizisinde buldum: https://stackoverflow.com/a/27165723/3709173

Özetlersek:

  1. modalPresentationStyle öğesini .Custom olarak ayarlayın
  2. alt sınıf UIPresentationController, shouldRemovePresentersView (NO ile) geçersiz kıl
  3. TransitionDelegate sınıfınızda PresentationControllerForPresentedViewController'ı geçersiz kılın ve özel UIPresentationController'ı döndürün

Özel geçişinizde +1, işten çıkarma animasyonu gerçekleşirken Görünüm'e eklemeyin.

Burada gösterildi:

https://www.dropbox.com/s/7rpkyamv9k9j18v/CustomModalTransition.zip?dl=0 herhangi bir hack olmadan! sihir gibi! :)


1
Bu gerçek doğru cevap. Kabul edilen numaradaki gibi sihir numaraları olmadan. Teşekkürler Mark!
Andrei Malygin

Ne yazık ki, bu iOS 12.4, Xcode 10.3'te çalışmıyor. Geçiş tamamlandıktan sonra ekran kararır (tüm görünümler hiyerarşiden kaldırılmıştır. Ancak, 'modalPresentationStyle' özelliğinin '.fullscreen' olarak ayarlanması İŞE ÇALIŞIR. Şerefe.
Womble

Mark ve gwinyai'nin Swift uygulamasından Obj-C versiyonunu projemde denedim. Ne yazık ki hiçbiri beklendiği gibi çalışmıyor. Xcode 11.1 kullanıyorum ve yapı hedefi iOS 13.0, hem cihazda hem de simülatörde denedim. Benim durumumda, temel kurulumum bir koleksiyon görünümüdür ve bir hücreye dokunduğunuzda, animasyonlu bir ayrıntı görünümüne geçecektir. Ancak, varsayılan geçiş animasyonunu kullanıyorsam tamamen iyi çalışıyor. Görünümden detaylardan devam ettiğimde sunum yapan VC gitmeyecek.
infinity_coding7

8

İOS 8'de, bir UIPresentationController oluşturmanız ve UIViewControllerTransitioningDelegate'de aşağıdaki yöntemi uygulamanız gerekir.

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

Temsilcinizden, bir görünüm denetleyicisini sunarken görünüm hiyerarşisini yönetmek için kullanmak üzere özel sunum denetleyicisini ister.

Geri dönüş değeri:

Modal sunumu yönetmek için özel sunum denetleyicisi.

Tartışma:

UIModalPresentationCustom sunum stilini kullanarak bir görünüm denetleyicisi sunduğunuzda, sistem bu yöntemi çağırır ve özel stilinizi yöneten sunum denetleyicisini ister. Bu yöntemi uygularsanız, sunum sürecini yönetmek için kullanmak istediğiniz özel sunum denetleyicisi nesnesini oluşturmak ve döndürmek için kullanın.

Bu yöntemi uygulamazsanız veya bu yöntemi uygulamanız sıfır döndürürse, sistem varsayılan bir sunum denetleyici nesnesi kullanır. Varsayılan sunum denetleyicisi, görünüm hiyerarşisine herhangi bir görünüm veya içerik eklemez.

Kullanılabilirlik iOS 8.0 ve sonrasında mevcuttur.

Daha fazla bilgi için WWDC 2014 videosunu izleyin:

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

Ayrıca WWDC'den WWDC 2014 örnek kod sayfasından indirebileceğiniz "LookInside: Sunum Denetleyicileri Uyarlama ve Özel Animatör Nesneleri" adlı örnek bir kod da bulunmaktadır.

Örnek kodu biraz değiştirmeniz gerekebilir. UIPresentationController başlatma yöntemi şu şekilde değiştirildi:

initWithPresentedViewController:presented presentingViewController:presenting

Sunulmadan önce ve sonra sunuldu. Sadece onları değiştirin ve işe yarayacaktır.


Bağlantılı videoyu izlemediğim için üzgünüm, ancak animasyon tamamlandıktan sonra dairesel sunulan görünüm gibi standart olmayan bir sunum istemediğiniz sürece özel bir UIPresentationController'a ihtiyacınız olduğunu sanmıyorum. Sadece farklı bir animasyon istiyorsanız, sınırlı bilgime dayanarak UIViewControllerAnimatedTransitioning'i uygulamak yeterli olacaktır.
Vaddadi Kartick

7

yerine [inView insertSubview: toViewController.view aboveSubview: fromViewController.view]; sadece şunu ekleyin: [inView addSubview: toViewController.view];

if (self.presenting) {

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

} else {
    // your code
}

Burada bir örnek görebilirsiniz: link ve iOS 7 ve iOS 8'de çalışıyor


Bu, fromViewController'ı containerView'a eklemeye gerek olmadığından, UIModalPresentationStyleCustom türü bir animasyon yapmak için kabul edilen yanıt olmalıdır. ToViewController'ı sadece sunum animasyonu sırasında eklemeniz gerekir.
Scott Kaiser

Bu gerçekten çok yardımcı oldu
Dmitry Bondarev

7

İşte Ash'in düzeltmesinin bir Hedef C versiyonu.

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

Düzgün çalışması için başka bir görünüm denetleyicisinin işten çıkarma tamamlama bloğundan yeni bir görünüm denetleyicisi sunmak için görünümü geri ekledikten sonra siparişi değiştirmem ve [transitionContext completeTransition:] yöntemini çağırmam gerekti.

Bunun herkes için düzelteceğini bilmiyorum ama uygulamamda çalışıyor. Şerefe!


5

Bunun Obj-C için iyi çalıştığını buldum:

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

Hem ios7 hem de ios8'de iyi çalışıyor gibi görünüyor.


5

Bunu buldum viewForKey:UITransitionContextToViewKeydöner iOS8 üzerinde nil. Yani sıfırsa, görünümü 'to' görünüm denetleyicisinden alırım.

Ancak bu completeTransition:YES, çağrıldığında kapsayıcıdan pencereye taşınmayan 'kime' görünümüyle sonuçlanıyor gibi görünüyor . Bu yüzden viewForKey:UITransitionContextToViewKeysıfır döndürürse, üzerine düşerim toVC.viewve sıfırın döndüğü gerçeğini takip ederim ve tamamlandıktan sonra onu konteynerin ilk denetimine (pencere olur) taşırım.

Bu kod -iOS7 eserlerin yanı sıra iOS8 Yani, ve gerektiği onlar bunu düzeltmek veya değilse de bile iOS9 üzerinde çalışmak.

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

Ayarladığınızda bu hatanın (ve çok daha fazlasının!) Ortadan kalktığını buldum modalPresentationStyle = UIModalPresentationFullScreen. Elbette hala özel geçiş animasyonunuzu alıyorsunuz.


2

Ben de bu konuya takılı kaldım. Geldiğim görüntü denetleyicisini hala görebildiğim yarı saydam bir arka plana sahip özel bir geçiş oluşturmak istiyordum, ancak yalnızca siyah bir arka planım var. Mark Aron'un bu konudaki cevabının bana yardımcı olduğunu buldum, ancak Objective C ile yazılmış, bu yüzden iOS 9 ve iOS 10 için test ettiğim cevabın Swift 3 sürümü burada:

  1. UIPresentationController'ın bir alt sınıfını oluşturun. ShouldRemovePresentersView öğesini aşağıdaki gibi false olarak geçersiz kılın:

    class ModalPresentationController: UIPresentationController {
    
    override var shouldRemovePresentersView: Bool {
    return false
    }
    
    override func containerViewWillLayoutSubviews() {
    presentedView?.frame = frameOfPresentedViewInContainerView
    }
    }
  2. Yeni görünüm denetleyicisini örneklediğiniz ve geçiş temsilcisini ayarladığınız yerde, aşağıdaki gibi özel bir modal sunum stili göstermesini istediğinizi belirtin:

    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. Şimdi UIViewControllerTransitioningDelegate'ınızın PresentationController yöntemini geçersiz kılın ve özel UIPresentationController'ınızı iade edin. Benimki mevcut sınıfımın bir uzantısı olarak vardı:

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

Unutulmaması gereken bir diğer nokta da, presentAnimator sınıfınızda fromView'unuza başvurmamalısınız. Bu sıfır olacak ve çalışma zamanında bir hata alacaksınız. Bunun dışında, benzer şeyler uygularsanız, animasyonu ve yarı şeffaf bir arka plan ile özel geçişinizi elde edersiniz.


Bu iis, Swift 3'te özel bir modal sunum yapmak için harika bir örnek! Teşekkürler @gwinyai! Yeni hızlı 3 API'sini gösteren bir örnek bulana kadar bu konuda çok sıkışıp kaldım presentationController(forPresented presented UIViewController,... çünkü önceki hızlı API, derleyiciyi üzmedi, ancak çağrılmadı.
Natalia

2

Bu sorunla karşılaştıktan sonra kafam çok karıştı, çünkü kısa süre önce neredeyse aynı olan ve işe yarayan bir şey yazmıştım. Buraya oldukça karmaşık görünen ve temel nedeni anlamayan düzeltmeleri bulmak için cevaplar aramak için geldim ... Aslında düzeltmesi çok kolay.

Bazı yanıtlar değişiyor sayılabilir modalPresentationStyleiçin .overFullScreen. Bu doğru, .overCurrentContextişe yarardı. Bu beklenen ve Apple'ın belgelediği davranış. Ama bu neden herkes için işe yaramıyor? Neden tüm hacky kodlar ve bunların başka bir şeyle kombinasyonları ve yapmamanız gereken çılgın şeyler?

Görünüşe göre, GÖRÜNÜM YÜKLERİNDEN ÖNCE sunum stilini ayarlamanız gerekiyor . Sonra değil. Bunu init içinde yapın veya önceki denetleyiciden yapın veya istediğiniz gibi yapın - görünüm yüklenmeden önce olduğu sürece.


1
Sunum stilini .overCurrentContext görünüm yükünden önceye ayarladım ( initgörünüm denetleyicisinin içinde) ve sorun hala devam ediyor
ricardopereira

1

Yeni UIModalPresentationOverCurrentContext'i kullanmak benim için sorunu çözdü. İOS 7'deki orijinal geçişim, modalin altında görüntünün bulanık bir arka planına sahip olmaktı.


Bazı nedenlerden dolayı, bu, iOS 7'de UIModalPresentationCurrentContext'in yaptığı, alttaki görünümle etkileşime izin vermiyor gibi görünüyor .. Herhangi bir fikriniz var mı?
Christopher Wirt

Benim için iOS 10'da Hmm, .overCurrentContext bu hataya neden olur, ancak .fullscreen sonuçlanmaz. Buraya .overCurrentContext'i kullanmak için bir düzeltme umarak geldim ama şu ana kadar iOS 10'da UIPresentationController'ın alt sınıflaması dışında hiçbir şey çalışmayacak gibi görünmüyor ...
Natalia

0

Tamam beyler, iOS 13 ve üzeri sürümlerde uygulama oluşturduğunuzda 'çalışan bir animatörün düzgün çalışmayı durdurduğu bir durumu çözdüğümü düşünüyorum.

Env Xcode 11.1, iOS 13.1

Sorun

Yapmak istediğim şey çok basit: Koleksiyon görünümüm var, bir hücreye dokunulduğunda, ayrıntılı bir görünüme geçecek. Sıkıcı varsayılan 'modal olarak mevcut' stilini kullanmak yerine, onu daha ilginç hale getirmek istiyorum, bu yüzden görünüm denetleyicisi geçişi için bir animatör yazdım.

Segue'yu koleksiyon VC'mden ayrıntı VC'ye sürükleyip bırakarak IB'de kuruyorum. Segue stili "Mod olarak mevcut" ve sunum "Tam Ekran" olarak ayarlandı.

Ayrıntılı görünümü gösterdiğinde, her şey beklendiği gibi çalışır. Ancak, ayrıntı görünümünü kapattığımda ve koleksiyon görünümüne döndüğümde, yalnızca animasyonlu ayrıntı görünümünü görebiliyorum, koleksiyon görünümü kayboldu. Oraya buraya dürttü ve birkaç keşifim var

1. 'animateTransition ()' işlevinden aşağıdaki satır çağrıldıktan hemen sonra, koleksiyon görünümü devam eder ve görünür

transitionContext.completeTransition(true)

2. Ayrıntılı görünüm, koleksiyon görünümünü tam olarak kapsamadığı sürece, koleksiyon görünümü ayrıntı görünümünden geri döndüğünde kaybolmayacaktır.

Çözüm

Dürüst olmak gerekirse, animasyonlu geçişin nasıl çalıştığı hakkında çok az şey biliyorum. Bu yüzden sadece bu yazıyı takip edebilirim ve diğerini , cevapların her birini deneyebilirim. Ne yazık ki hiçbiri benim için çalışmıyor. Sonunda, ince ayar yapabileceğim tek şeyin IB'deki segmentin sunum stili olduğu bir noktaya geldim (bunu en baştan yapmalıydım). Sunumu 'Tam Ekran' olarak ayarladığımda mucize oluyor ve sorunum çözülüyor. Detay görünümü animasyonla birlikte tam ekran olarak gösterilebilir ve kapatıldığında hem koleksiyon görünümünü arka plan hem de animasyonlu detay görünümü olarak görebilirim.

Sonra yol boyunca bir keşif daha

3. 'toView' ve 'fromView' ifadelerine başvurmak için aşağıdaki yöntemlerin ikisi de çalışır

Dolaylı yol:

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

Doğrudan yol:

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

Ancak segment stilini 'Tam Ekran Üzerinde' olarak değiştirdiğimde, hem 'toView' hem de 'fromView' için doğrudan geri dönüş 'nil' ve yalnızca dolaylı olarak işe yarıyor, bu sorundan başka bir gönderide de bahsediliyor , bu yüzden buna değer olduğunu düşünüyorum küçük keşfimi buraya göndermek için.

Umarım bu gelecekte birine yardımcı olur.


0

Bir içerik görüntüleme denetleyicisini kapatırken de aynı sorunu yaşıyordum.

Uygulamamda, alt görünüm denetleyicisini (vc sunan) modsal olarak gösteren bu üst görünüm denetleyicisi var. Daha sonra, childVC'deki bir alt görünüme dokunulduğunda, başka bir vc'yi gösterir (ben içerik görüntüleme denetleyicisini çağırıyorum (sunulan vc))

Benim sorunum, contentVC'yi (şimdi sunulan vc) kapatırken, alt VC'ye (şimdi sunulan VC) gitmesi gerektiğidir, ancak özel geçişim biter bitmez, childVC aniden kaybolur ve ana VC'yi gösterir.

Bu sorunu çözmek için yaptığım şey

  1. değiştirmek .modalPresentationStylechildVC varsayılan gelen parentVC sunduğu .automaticiçin .fullscreen.
  2. Daha sonra .modalPresentationStylecontentVC .fullscreende değiştirildi.

Bu sorunu çözer. ancak çocuğunuzun VC'sini .overCurrentContext, iOS 13'te yeni olan parentVC'nin (kullanırken veya otomatik olarak) üzerinde kart tarzı bir sayfa olarak göstermez .

Ebeveyn tarafından sunulduğunda childVC için kart stilindeki sayfayı koruyacak herhangi bir çözüm olup olmadığını bilmek isterim.


-3

başka bir görünüm denetleyicisinin alt öğesi olarak bir görünüm denetleyicisi ekler.

[self addChildViewController:childViewController];                 

kontrol edin ve bana bildirin.


anlamıyorum, kodlama kullanarak anlatabilir misin?
NiravPatel

bu elma dokümantasyonuna bakın geliştirici.apple.com
library/ios/featuredarticles/…

bu hiçbir şekilde soruyu cevaplamaz. ChildViewControllers, özel geçişlerin herhangi bir bölümüne dahil değildir, tamamen farklı bir konudur.
Andras M.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.