“From View Controller” menghilang menggunakan UIViewControllerContextTransitioning

105

Saya punya satu masalah dan saya telah menjelaskannya di bawah ini.

Saya menggunakan UIViewControllerContextTransitioninguntuk transisi khusus.

Saya memiliki 2 pengontrol tampilan, pengontrol tampilan pertama dan pengontrol tampilan kedua.

Sekarang saya ingin menambahkan pengontrol tampilan kedua pada pengontrol tampilan pertama dengan animasi. Saya telah mencapainya, sekarang pengontrol tampilan kedua transparan, jadi kita bisa melihat pengontrol tampilan pertama di bawah pengontrol tampilan kedua.

Tetapi saya tidak dapat melihat pengontrol tampilan pertama, dan saya hanya dapat melihat layar hitam di bawah pengontrol tampilan kedua.

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

Saat [self.transitionContext completeTransition:YES];dipanggil, tiba-tiba pengontrol tampilan pertama menghilang dan layar hitam ditampilkan di bawah pengontrol tampilan kedua.

Apakah ada yang punya ide? Terima kasih.

NiravPatel
sumber

Jawaban:

98

Saya mengalami masalah yang sama di sini - sepertinya ada bug di iOS 8. Saya telah mengajukan radar .

Saya menggunakan Reveal untuk memeriksa hierarki tampilan setelah layar menjadi hitam. Kuncinya UIWindowbenar-benar kosong - sama sekali tidak ada hierarki tampilan!

Terungkap

Saya bermain-main sedikit dan sepertinya ada solusi yang mudah, untuk kasus sederhana. Anda bisa menambahkan kembali toViewControllertampilan sebagai subview dari jendela kunci:

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

Saya telah memeriksa dan jendela kuncinya rootViewControllermasih disetel dengan benar, jadi tidak apa-apa. Saya tidak yakin apa yang akan terjadi jika Anda mempresentasikan pengontrol Anda dari dalam pengontrol modal yang sudah disajikan, jadi untuk kasus yang lebih kompleks, Anda harus bereksperimen.

Ash Furrow
sumber
2
Saya juga melihat masalah ini. iOS 8 memperkenalkan metode dan kunci baru untuk mengakses fromView dan toView (Catatan: bukan pengontrol tampilan) Tampaknya referensi ini tidak hilang selama transisi. Anda dapat menambahkannya ke tampilan penampung seperti biasa jika Anda baru saja mengambilnya dari pengontrol tampilan.
tapi
1
Saya melihat keanehan iOS 8 yang serupa ketika mencoba menambahkan subview ke tampilan pengontrol navigasi saya, di viewDidLoad. Menambahkan kembali tampilan navigationController ke keyWindow sepertinya berhasil, terima kasih banyak, Ash!
taber
1
Saya masih melihat ini di GM (dan perbaikan ini masih berfungsi). Apakah orang lain melihat hal yang sama? Apakah ini hanya perubahan pada API?
rjkaplan
21
Saya menemukan bahwa bug ini (dan banyak lagi!) Lenyap jika Anda menyetelnya modalPresentationStyle = UIModalPresentationFullScreen. Anda tentu saja masih mendapatkan animasi transisi kustom Anda.
Chris
1
Terima kasih @AshFurrow. Solusi bagus sampai diperbaiki!
kandelvijaya
78

Saya merasa alasan di balik ini harus dijelaskan dengan lebih baik.

Tampilan tersebut menghilang karena Anda mengeluarkan tampilan pengontrol tampilan penyajian dari lokasi aslinya (hierarki tampilan), meletakkannya di dalam containerView yang disediakan oleh animator Anda tetapi tidak pernah mengembalikannya setelah animasi selesai. Sehingga tampilan pengontrol tampilan dihapus dengan superview (containerView) dari jendela sepenuhnya.

Di iOS 7, sistem selalu mengembalikan tampilan pengontrol tampilan yang terlibat dalam presentasi (menyajikan dan disajikan) ke tempat aslinya setelah transisi selesai dianimasikan secara otomatis. Itu tidak lagi terjadi untuk beberapa gaya presentasi di iOS 8.

Aturannya sangat sederhana: animator hanya boleh memanipulasi tampilan pengontrol tampilan penyajian jika tampilan pengontrol tampilan tersebut akan disembunyikan (dihapus dari hierarki tampilan) sepenuhnya pada akhir transisi . Dengan kata lain, ini berarti bahwa setelah animasi presentasi awal selesai, hanya tampilan pengontrol tampilan yang disajikan yang akan terlihat, bukan tampilan pengontrol tampilan yang menyajikan. Misalnya, jika Anda menyetel opasitas tampilan pengontrol tampilan yang disajikan menjadi 50% dan menggunakan UIModalPresentationFullScreen, Anda tidak akan dapat melihat tampilan pengontrol tampilan di bawah yang disajikan, tetapi jika Anda menggunakan UIModalPresentationOverFullscreen - Anda akan melakukannya ( shouldRemovePresentersViewmetode UIPresentationController bertanggung jawab untuk menentukannya).

Mengapa tidak mengizinkan animator memanipulasi tampilan pengontrol tampilan presentasi setiap saat? Pertama-tama, jika tampilan pengontrol tampilan penyajian akan tetap terlihat setelah animasi selesai selama seluruh siklus hidup presentasi, tidak perlu menganimasikannya sama sekali - itu hanya tetap di tempatnya. Kedua, jika kepemilikan untuk pengontrol tampilan tersebut ditransfer ke pengontrol presentasi, pengontrol presentasi kemungkinan besar tidak akan tahu bagaimana menata letak tampilan pengontrol tampilan tersebut saat diperlukan misalnya ketika orientasi berubah, tetapi pemilik asli dari pengontrol tampilan yang menyajikan tidak .

Di iOS 8 viewForKey:metode diperkenalkan untuk mendapatkan tampilan yang dimanipulasi oleh animator. Pertama, ada baiknya untuk mengikuti aturan yang dijelaskan di atas dengan mengembalikan nol setiap kali animator tidak boleh menyentuh tampilan. Kedua, ini mungkin mengembalikan tampilan berbeda untuk animator untuk dianimasikan. Bayangkan Anda sedang melaksanakan presentasi yang mirip dengan lembar formulir. Dalam hal ini Anda ingin menambahkan bayangan atau hiasan di sekitar tampilan pengontrol tampilan yang disajikan. Animator akan menganimasikan dekorasi itu dan tampilan pengontrol tampilan yang disajikan akan menjadi turunan dari dekorasi.

viewControllerForKey: tidak hilang, ini masih dapat digunakan jika akses langsung ke pengontrol tampilan diperlukan tetapi animator tidak boleh membuat asumsi apa pun tentang tampilan yang diperlukan untuk dianimasikan.

Ada beberapa hal yang dapat Anda lakukan untuk benar memperbaiki masalah dengan pandangan menghilang menyajikan controller tampilan ketika Anda secara eksplisit menempatkannya dalam pandangan wadah animator ini:

  1. Jika tidak perlu menganimasikan tampilan pengontrol tampilan penyajian, gunakan viewForKey:agar tampilan dianimasikan daripada menjangkau tampilan pengontrol secara langsung. viewForKey:dapat mengembalikan pandangan nihil atau bahkan sama sekali berbeda.

  2. Jika Anda ingin menganimasikan tampilan pengontrol tampilan penyajian, Anda harus mempertimbangkan untuk menggunakan UIModalPresentationFullScreengaya atau terus menggunakan UIModalPresentationCustomdan mengimplementasikan subkelas UIPresentationController Anda sendiri dengan shouldRemovePresentersViewmengembalikan YES. Faktanya, penerapan metode ini adalah perbedaan utama antara pengontrol presentasi internal yang ditentukan oleh UIModalPresentationFullScreendan UIModalPresentationCustomgaya terlepas dari fakta bahwa yang terakhir memungkinkan Anda untuk menggunakan pengontrol presentasi kustom.

  3. Dalam semua kasus yang jarang terjadi, Anda harus mengembalikan tampilan pengontrol tampilan penyajian ke lokasi aslinya seperti yang disarankan jawaban lain.

egdmitry
sumber
2
Itu super aneh karena kode ini bergantung pada viewControllerForKey:'s views hanya ketika viewForKey:kembali nil, dan saya masih harus menambahkannya kembali ke jendela secara manual. Apakah Anda memiliki contoh kode yang berfungsi tanpa solusi ini?
Ash Furrow
Nah, jika viewForKey:mengembalikan nihil maka pasti Anda harus menambahkan kembali tampilan pengontrol tampilan presentasi ke jendela jika Anda menghapusnya di animator Anda. Jika viewForKey mengembalikan tampilan pengontrol tampilan sebenarnya, aman untuk memindahkan tampilan itu karena UIKit akan memindahkannya kembali ke posisi semula setelah siklus hidup presentasi selesai.
egdmitry
Terima kasih telah menjelaskan alasan di balik masalah ini. Anda benar sekali. Memindahkan posisi tampilan dalam hierarki tampilan tanpa menggantinya jelas akan membuatnya menghilang (posting iOS 8, dan saya sedang bekerja dengan iOS 10 sekarang!) Terima kasih telah mengklarifikasi.
Clay Ellis
1
Terima kasih egdmitry atas klarifikasi Anda. Yang menimbulkan pertanyaan lain yaitu: menurut Anda bagaimana saya harus menerapkan presentasi seperti pengungkapan ? Salah satu yang sangat umum saat ini di mana tampilan penyajian bergeser keluar sebagian untuk menunjukkan tampilan yang disajikan di bawahnya? Dalam skenario ini, tampilan penyajian dan penyajian harus ada di layar dan tampilan penyajian adalah yang dianimasikan.
Andrea
70

Di iOS 8, Anda harus memanipulasi tampilan yang dikembalikan oleh viewForKey:alih-alih .viewproperti pengontrol tampilan yang dikembalikan oleh viewControllerForKey:. Ini tidak terlalu jelas dari dokumentasi beta, tetapi jika Anda melihat sumber untuk UIViewControllerTransitioning.h Anda akan melihat komentar ini di atas 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;

Jadi, alih-alih menyesuaikan bingkai, dll. toViewController.view, Gunakan nilai kembalian [transitionContext viewForKey:UITransitionContextToViewKey].

Jika aplikasi Anda perlu mendukung iOS7 dan / atau Xcode 5, Anda dapat menggunakan metode kategori sederhana di UIViewController seperti berikut:

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

Kemudian, dapatkan milik Anda toViewControllerdan fromViewControllerseperti biasa, tetapi dapatkan tampilan menggunakan [toViewController viewForTransitionContext:transitionContext].

Sunting: Tampaknya ada bug, di mana tampilan pengontrol tampilan penyajian adalah nol saat dikembalikan dari viewForKey, yang mencegah Anda membuat transisi modal yang menganimasikan tampilan penyajian sama sekali (seperti menggeser off, atau membalik-horizontal). Saya melaporkan bug untuk iOS8 di rdar: // 17961976 ( http://openradar.appspot.com/radar?id=5210815787433984 ). Lihat juga proyek sampel di http://github.com/bcherry/TransitionBug

Sunting 2: Terima kasih kepada graveley atas sarannya, menggunakan UIModalPresentationFullScreen memperbaiki masalah. Mungkin ini bukan bug. Apple mungkin bermaksud agar UIModalPresentationCustom hanya mengubah tampilan modal masuk. Jika Anda ingin mengubah tampilan keluar, Anda perlu menjamin presentasi layar penuh dari tampilan baru? Bagaimanapun, Anda harus menggunakan viewForKeydan UIModalPresentationFullScreen.

bcherry.dll
sumber
2
Bug viewForKey membuatku gila! - terima kasih sudah mengajukan. FWIW transisi saya berfungsi dengan baik dengan mendapatkan tampilan dari UITransitionContextToViewControllerKey, tetapi transisi saya hanya menerapkan transformasi ke seluruh tampilan. Saya tidak yakin apakah itu harus ditafsirkan sebagai manipulatingpandangan VC atau tidak ...
MathewS
1
Wow - itu gila. Saya tidak melihatnya di diff - mungkin karena itu hanya komentar kecil. Benar-benar frustasi ketika Apple melakukan aksi seperti ini. Semoga sukses tentang radar Anda.
Ash Furrow
Saya melihat viewForKeybug di GM juga. Apakah orang lain juga? Sudahkah Anda menemukan solusi yang masuk akal untuk itu?
rjkaplan
2
Saya pikir menurut komentar - viewForKey// viewForKey: mungkin mengembalikan nihil yang akan menunjukkan bahwa animator tidak boleh memanipulasi tampilan pengontrol tampilan terkait. Kembali nilbukanlah bug.
Ken Kuan
4
@kenKuan Anda mungkin benar. saat menggunakan UIModalPresentationFullScreen, viewForKeymengembalikan tampilan dari dan ke tampilan. Jadi mungkin disengaja ia mengembalikan nihil untuk UIModalPresentationCustom. Saya memperbarui laporan bug saya dan akan memposting kembali di sini jika saya mendapat kabar dari Apple tentang hal itu.
bcherry
24

Tidak menyetel modalPresentationStyleke UIModalPresentationCustom memperbaiki masalah saya.

Dengan kata lain, tetap menggunakan default UIModalPresentationFullScreen alih-alih menentukan UIModalPresentationCustom memperbaiki masalah tampilan menghilang. Perhatikan bahwa protokol UIViewControllerTransitioningDelegate tampaknya masih diikuti bahkan ketika membiarkannya di default. Jika saya ingat dengan benar, sekali waktu UIModalPresentationCustom adalah persyaratan.

Bekerja sejauh ini, hanya mencoba ini untuk animasi non-interaktif.

berkerikil
sumber
1
Wow. Berhasil! Saya menguji tanpa modalPresentationStyle di iOS7 & 8 dan berhasil menemukan keduanya. Terima kasih!!
Ah Ryun Moon
1
Terima kasih! Hal ini dikombinasikan dengan menggunakan viewForKey:bukannya .viewpada viewControllerForKey:perbaikan semua masalah bagi saya.
bcherry
1
Ini memperbaiki masalah untuk saya tanpa menggunakan viewForKey, tapi saya rasa itu harus digunakan juga.
Kevin Sliech
5
Meskipun ini tampaknya menyelesaikan masalah, penting untuk dicatat bahwa layar di belakang pengontrol tampilan Anda akan menjadi hitam setelah ditampilkan. Ini penting jika pengontrol tampilan Anda bukan layar penuh.
Pria
16

Saya telah menemukan jawaban yang sangat berguna ini dalam utas terkait oleh Lefteris: https://stackoverflow.com/a/27165723/3709173

Singkatnya:

  1. setel modalPresentationStyle ke .Custom
  2. subclass UIPresentationController, ganti shouldRemovePresentersView (dengan NO)
  3. ganti presentasiControllerForPresentedViewController di kelas TransitionDelegate Anda dan kembalikan UIPresentationController kustom Anda

+1 dalam transisi ubahsuaian Anda, jangan tambahkan keTampilan saat animasi penutupan terjadi.

Ditunjukkan di sini:

https://www.dropbox.com/s/7rpkyamv9k9j18v/CustomModalTransition.zip?dl=0 tanpa peretasan! itu seperti sulap! :)

Mark Aron Szulyovszky
sumber
1
Ini adalah jawaban yang benar. Tanpa trik sulap seperti yang diterima. Terima kasih, Mark!
Andrei Malygin
Sayangnya, ini tidak berfungsi di iOS 12.4, Xcode 10.3. Layar menjadi hitam setelah transisi selesai (semua tampilan telah dihapus dari hierarki. Namun, menyetel properti 'modalPresentationStyle' ke '.fullscreen' TIDAK BERFUNGSI. Salam.
Womble
Saya mencoba versi Obj-C dari implementasi Swift Mark dan gwinyai dalam proyek saya. Sayangnya tidak ada yang berfungsi seperti yang diharapkan. Saya menggunakan Xcode 11.1 dan target build adalah iOS 13.0, saya mencoba pada perangkat dan simulator. Dalam kasus saya, pengaturan dasar saya adalah tampilan koleksi dan ketika Anda mengetuk satu sel, itu akan beralih ke tampilan detail dengan animasi. Namun, ini berfungsi dengan baik jika saya menggunakan animasi transisi default. VC presentasi tidak akan hilang ketika saya melanjutkan dari tampilan detail.
infinity_coding7
8

Di iOS 8, Anda perlu membuat UIPresentationController dan mengimplementasikan metode di bawah ini, di UIViewControllerTransitioningDelegate.

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

Meminta delegasi Anda untuk menggunakan pengontrol presentasi kustom untuk mengelola hierarki tampilan saat menyajikan pengontrol tampilan.

Nilai Kembali:

Pengontrol presentasi kustom untuk mengelola presentasi modal.

Diskusi:

Saat Anda menyajikan pengontrol tampilan menggunakan gaya presentasi UIModalPresentationCustom, sistem akan memanggil metode ini dan meminta pengontrol presentasi yang mengelola gaya kustom Anda. Jika Anda menerapkan metode ini, gunakan untuk membuat dan mengembalikan objek pengontrol presentasi kustom yang ingin Anda gunakan untuk mengelola proses presentasi.

Jika Anda tidak mengimplementasikan metode ini, atau jika implementasi metode ini menghasilkan nihil, sistem menggunakan objek pengontrol presentasi default. Pengontrol presentasi default tidak menambahkan tampilan atau konten apa pun ke hierarki tampilan.

Ketersediaan Tersedia di iOS 8.0 dan yang lebih baru.

Untuk informasi lebih lanjut, tonton video WWDC 2014:

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

Ada juga kode contoh dari WWDC yang disebut "LookInside: Presentation Controllers Adaptivity and Custom Animator Objects", yang dapat Anda unduh dari halaman kode contoh WWDC 2014.

Anda mungkin perlu sedikit mengubah kode sampel. Metode init UIPresentationController diubah menjadi:

initWithPresentedViewController:presented presentingViewController:presenting

Sebelum dipresentasikan dan kemudian dipresentasikan. Tukar saja dan itu akan berhasil.

Paulo Faria
sumber
Maaf karena tidak menonton video yang ditautkan, tetapi menurut saya Anda tidak memerlukan UIPresentationController khusus kecuali Anda menginginkan presentasi non-standar setelah animasi selesai, seperti tampilan yang disajikan melingkar. Jika Anda hanya ingin animasi yang berbeda, mengimplementasikan UIViewControllerAnimatedTransitioning sudah cukup, berdasarkan pengetahuan saya yang terbatas.
Vaddadi Kartick
7

bukannya [inView insertSubview: toViewController.view aboveSubview: fromViewController.view]; cukup tambahkan: [inView addSubview: toViewController.view];

if (self.presenting) {

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

} else {
    // your code
}

Anda dapat melihat contohnya di sini: tautan dan berfungsi di iOS 7 dan iOS 8

CarlosGz
sumber
Ini harus menjadi jawaban yang diterima untuk melakukan jenis animasi UIModalPresentationStyleCustom karena tidak perlu menambahkan fromViewController ke containerView. Anda hanya perlu menambahkan toViewController selama animasi presentasi.
Scott Kaiser
Ini sebenarnya sangat membantu
Dmitry Bondarev
7

Ini adalah versi Objective C dari perbaikan 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]

Saya harus menukar urutan dan memanggil metode [transisiContext completeTransition:] setelah menambahkan tampilan kembali untuk mendapatkan penyajian pengontrol tampilan baru dari blok penyelesaian pemecatan dari pengontrol tampilan lain untuk bekerja dengan benar.

Saya tidak tahu bahwa ini akan memperbaikinya untuk semua orang tetapi berfungsi di aplikasi saya. Bersulang!

vichudson1
sumber
5

Saya menemukan ini berfungsi dengan baik untuk Obj-C:

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

Sepertinya bekerja dengan baik di ios7 dan ios8.

Melengking
sumber
5

Saya menemukan bahwa viewForKey:UITransitionContextToViewKeymengembalikan nol pada ios8. Jadi jika nihil, saya ambil view dari 'to' view controller.

Namun, hal ini tampaknya mengakibatkan tampilan 'ke' tidak dipindahkan dari penampung ke jendela saat completeTransition:YESdipanggil. Jadi jika viewForKey:UITransitionContextToViewKeymengembalikan nihil, saya jatuh ke toVC.view, dan melacak fakta bahwa itu kembali nihil, dan setelah selesai saya memindahkannya ke tampilan awal wadah (yang kebetulan jendela).

Jadi kode ini berfungsi di iOS7 serta iOS8, dan harus berfungsi di iOS9 juga meskipun mereka memperbaikinya atau tidak.

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

Saya menemukan bahwa bug ini (dan banyak lagi!) Lenyap jika Anda menyetelnya modalPresentationStyle = UIModalPresentationFullScreen. Anda tentu saja masih mendapatkan animasi transisi kustom Anda.

Chris
sumber
2

Saya juga terjebak dalam masalah ini. Saya sedang mencari untuk membuat transisi kustom dengan latar belakang semi-transparan di mana saya masih bisa melihat pengontrol tampilan saya berasal tetapi saya hanya mendapatkan latar belakang hitam. Saya menemukan jawaban Mark Aron di utas ini membantu saya tetapi itu ditulis di Objective C jadi inilah versi Swift 3 dari jawaban itu yang telah saya uji untuk iOS 9 dan iOS 10:

  1. Buat subclass UIPresentationController. Ganti shouldRemovePresentersView menjadi false sebagai berikut:

    class ModalPresentationController: UIPresentationController {
    
    override var shouldRemovePresentersView: Bool {
    return false
    }
    
    override func containerViewWillLayoutSubviews() {
    presentedView?.frame = frameOfPresentedViewInContainerView
    }
    }
  2. Di tempat Anda membuat instantiating pengontrol tampilan baru dan menyetel delegasi transisinya, tunjukkan bahwa Anda ingin menampilkan gaya presentasi modal kustom sebagai berikut:

    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. Sekarang ganti metode presentasiController dari UIViewControllerTransitioningDelegate Anda dan kembalikan UIPresentationController kustom Anda. Saya memiliki milik saya sebagai perpanjangan dari kelas saya saat ini:

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

Satu hal lain yang perlu diperhatikan adalah Anda tidak boleh mencoba dan mereferensikan fromView di kelas presentAnimator Anda. Ini akan menjadi nol dan Anda akan mendapatkan kesalahan saat runtime. Selain itu jika Anda menerapkan hal-hal seperti hal-hal, Anda akan mendapatkan transisi khusus dengan animasinya dan latar belakang semi transparan jika Anda membuatnya.

gwinyai
sumber
Iis ini adalah contoh yang bagus untuk melakukan presentasi modal kustom di Swift 3! Terima kasih @gwinyai! Saya sangat terjebak dalam hal ini sampai saya menemukan contoh yang menunjukkan API 3 cepat baru presentationController(forPresented presented UIViewController,... karena API cepat sebelumnya tidak mengecewakan pemohon tetapi tidak dipanggil.
Natalia
2

Setelah menghadapi masalah ini, saya sangat bingung, karena saya telah menulis sesuatu yang hampir sama belum lama ini yang berfungsi dengan baik. Datang ke sini mencari jawaban untuk menemukan perbaikan yang terlihat cukup hack, dan sepertinya tidak memahami akar penyebabnya ... sebenarnya sangat mudah untuk diperbaiki.

Beberapa jawaban menyebutkan berubah modalPresentationStylemenjadi .overFullScreen. Ini benar, .overCurrentContextakan berhasil juga. Ini diharapkan, dan perilaku dokumen Apple. Tetapi mengapa ini tidak berhasil untuk semua orang? Mengapa semua kode hacky, dan kombinasinya dengan sesuatu yang lain, dan hal-hal gila yang tidak boleh Anda lakukan?

Ternyata, Anda perlu mengatur gaya presentasi SEBELUM TAMPILAN BEBAN . Tidak setelahnya. Lakukan di init, atau lakukan dari pengontrol sebelumnya, atau sesuka Anda - selama itu sebelum tampilan dimuat.

Jordan Smith
sumber
1
Saya mengatur gaya presentasi ke .overCurrentContext sebelum tampilan dimuat (di initpengontrol tampilan) dan masalah masih terjadi
ricardopereira
1

Menggunakan UIModalPresentationOverCurrentContext baru memperbaikinya untuk saya. Transisi asli saya di iOS 7 hanya memiliki latar belakang kabur dari tampilan di bawah modal.

malhal
sumber
Untuk beberapa alasan, ini tampaknya tidak memungkinkan interaksi dengan tampilan di bawah, yang dilakukan UIModalPresentationCurrentContext di iOS 7 .. Ada pendapat?
Christopher Wirt
Hmm bagi saya di iOS 10, .overCurrentContext menghasilkan bug ini, tetapi .fullscreen tidak. Saya datang ke sini berharap untuk memperbaiki penggunaan .overCurrentContext tetapi sejauh ini sepertinya tidak ada yang berfungsi di iOS 10 kecuali mungkin subclassing UIPresentationController ...
Natalia
0

Oke, teman-teman, saya pikir saya menyelesaikan satu kasus bahwa 'animator yang berfungsi' berhenti berfungsi dengan baik ketika Anda membangun aplikasi di iOS 13 dan lebih tinggi.

Env Xcode 11.1, iOS 13.1

Masalah

Yang ingin saya lakukan sangat sederhana: Saya memiliki tampilan koleksi, ketika sel diketuk, sel akan beralih ke tampilan detail. Alih-alih menggunakan gaya default yang membosankan dari 'present modally', saya ingin membuatnya lebih menarik, jadi saya menulis animator untuk transisi pengontrol tampilan.

Saya mengatur segue di IB dengan drag-and-drop dari VC koleksi saya ke detail VC. Gaya segue adalah 'Present modally' dan presentasi diatur ke 'Full Screen'.

Ketika itu menunjukkan tampilan detail, semuanya bekerja seperti yang diharapkan. Namun, saat saya mengabaikan tampilan detail dan kembali ke tampilan koleksi, saya hanya dapat melihat tampilan detail animasi, tampilan koleksi hilang begitu saja. Saya menyodok di sana-sini dan saya memiliki beberapa penemuan

1. Tepat setelah baris berikut dipanggil dari fungsi 'animateTransition ()', tampilan koleksi dilanjutkan dan muncul

transitionContext.completeTransition(true)

2. Selama tampilan detail tidak sepenuhnya menutupi tampilan koleksi, tampilan koleksi tidak akan hilang saat kembali dari tampilan detail

Larutan

Sejujurnya, saya hanya tahu sedikit tentang cara kerja transisi animasi. Jadi saya hanya bisa mengikuti postingan ini dan yang lainnya , coba masing-masing jawabannya. Sayangnya, tidak ada yang berhasil untuk saya. Akhirnya, saya sampai pada titik di mana satu-satunya hal yang dapat saya atur adalah gaya presentasi segue di IB (yang seharusnya saya lakukan di awal). Ketika saya mengatur presentasi ke 'Over Full Screen', keajaiban terjadi dan masalah saya terpecahkan. Tampilan detail dapat ditampilkan dalam layar penuh dengan animasi dan ketika ditutup, saya dapat melihat tampilan koleksi sebagai tampilan detail latar belakang dan animasi.

Kemudian satu penemuan lagi di sepanjang jalan

3. Untuk merujuk ke 'toView' dan 'fromView', kedua metode berikut berfungsi

Cara tidak langsung:

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

Cara langsung:

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

Tapi ketika saya mengganti gaya segue ke 'Over Full Screen', cara langsung mengembalikan 'nil' untuk 'toView' dan 'fromView' dan hanya cara tidak langsung berfungsi, masalah ini juga disebutkan di posting lain , jadi saya pikir itu layak untuk memposting penemuan kecil saya di sini.

Semoga ini bisa membantu seseorang di masa depan.

infinity_coding7
sumber
0

Saya mengalami masalah yang sama saat menutup pengontrol tampilan konten.

Aplikasi saya memiliki pengontrol tampilan orang tua yang menampilkan pengontrol tampilan anak (menampilkan vc) secara modally. Kemudian ketika subview di childVC disadap, itu menunjukkan vc lain (yang saya sebut pengontrol tampilan konten (disajikan vc))

Masalah saya adalah, ketika Menutup contentVC (sekarang vc presentasi), itu harus pergi ke VC anak (sekarang VC yang disajikan) tetapi segera setelah transisi kustom saya selesai, childVC tiba-tiba menghilang, menunjukkan VC induk.

Apa yang saya lakukan untuk mengatasi masalah ini adalah untuk

  1. ubah .modalPresentationStylechildVC yang disajikan oleh parentVC dari default .automaticmenjadi .fullscreen.
  2. Kemudian mengubah .modalPresentationStylecontentVC menjadi .fullscreenjuga.

Ini menyelesaikan masalah. tetapi itu tidak akan menampilkan VC anak Anda sebagai lembar bergaya kartu di atas parentVC (saat menggunakan.overCurrentContext atau otomatis) yang baru di iOS 13.

Ingin mengetahui apakah ada solusi yang akan mempertahankan lembar bergaya kartu untuk childVC saat disajikan oleh orang tua.

arvinq
sumber
-3

menambahkan pengontrol tampilan sebagai anak dari pengontrol tampilan lain.

[self addChildViewController:childViewController];                 

periksa dan beri tahu saya.

Rushabh
sumber
saya tidak mengerti, dapatkah Anda menjelaskannya menggunakan pengkodean?
NiravPatel
periksa dokumentasi apel ini developer.apple.com/library/ios/featuredarticles/…
Rushabh
ini sama sekali tidak menjawab pertanyaan itu. ChildViewControllers tidak terlibat dalam bagian mana pun dari transisi khusus, mereka adalah subjek yang sama sekali berbeda.
Andras M.