Bir UINavigationController'dan bir görünümü nasıl açabilirim ve bir işlemde onu bir başkasıyla değiştirebilirim?


84

Bir UINavigationController yığınından bir görünümü kaldırmam ve onu bir başkasıyla değiştirmem gereken bir uygulamam var. Durum, ilk görünümün düzenlenebilir bir öğe oluşturması ve ardından kendisini öğe için bir düzenleyiciyle değiştirmesidir. İlk bakışta bariz çözümü yaptığımda:

MyEditViewController *mevc = [[MYEditViewController alloc] initWithGizmo: gizmo];

[self retain];
[self.navigationController popViewControllerAnimated: NO];
[self.navigationController pushViewController: mevc animated: YES];
[self release];

Çok garip davranışlar alıyorum. Genellikle düzenleyici görünümü belirir, ancak gezinme çubuğundaki geri düğmesini kullanmaya çalışırsam, fazladan ekranlar alırım, bazıları boş ve bazıları da berbat. Başlık da rastgele hale geliyor. Gezinti yığını tamamen ıslatılmış gibi.

Bu soruna daha iyi bir yaklaşım ne olabilir?

Teşekkürler Matt

Yanıtlar:


137

Mülkle hiçbir şekilde manuel olarak uğraşmanıza gerek olmadığını keşfettim viewControllers. Temel olarak bununla ilgili 2 yanıltıcı şey var.

  1. self.navigationControllerdönecektir nileğer selfnavigasyon kontrolörün yığını şu anda değil. Bu nedenle, erişiminizi kaybetmeden önce yerel bir değişkene kaydedin.
  2. Yapmalısınız retain(ve gerektiği gibi release) selfya da içinde bulunduğunuz yönteme sahip olan nesnenin tahsisi kaldırılacak ve tuhaflığa neden olacaktır.

Bu hazırlığı yaptıktan sonra, normal şekilde patlatın ve itin. Bu kod anında üst denetleyiciyi bir başkasıyla değiştirecektir.

// locally store the navigation controller since
// self.navigationController will be nil once we are popped
UINavigationController *navController = self.navigationController;

// retain ourselves so that the controller will still exist once it's popped off
[[self retain] autorelease];

// Pop this controller and replace with another
[navController popViewControllerAnimated:NO];
[navController pushViewController:someViewController animated:NO];

Bu son satırda değiştirmek eğer animatedhiç YESardından yeni ekran aslında hareketlendirmek ve sadece attı denetleyici dışarı animasyon olacaktır. Oldukça hoş görünüyor!


parlak! çok daha iyi bir çözüm
emmby

Harika. [[Kendi kendini koruma] otomatik serbest bırakma] 'yı aramam gerekmese de, yine de iyi çalışıyor.
iamj4de

4
Belki bariz bir ekleme olabilir, ancak daha sonra geçişi canlandırmak için yukarıdaki kodu bir animasyon bloğuna koyabilirsiniz: [UIView beginAnimations: @ "View Flip" context: nil]; [UIView setAnimationDuration: 0.80]; [UIView setAnimationCurve: UIViewAnimationCurveEaseInOut]; [UIView setAnimationTransition: UIViewAnimationTransitionFlipFromRight forView: navController.view önbelleği: HAYIR]; [navController pushViewController: newController animasyonlu: YES]; [UIView commitAnimations];
Martin

11
Yalnızca tutma / otomatik bırakma hattını kaldırarak ARC ile harika çalışıyor.
Ian Terrell

2
@TomerPeled Evet, bu cevap yaklaşık 5 yaşında ... Sanırım iOS 3'te de durum böyleydi. API'ler yeterince değişti, artık bunun en iyi cevap olduğundan emin değilim.
Alex Wayne

56

Aşağıdaki yaklaşım bana daha hoş görünüyor ve aynı zamanda ARC ile de iyi çalışıyor:

UIViewController *newVC = [[UIViewController alloc] init];
// Replace the current view controller
NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:[[self navigationController] viewControllers]];
[viewControllers removeLastObject];
[viewControllers addObject:newVC];
[[self navigationController] setViewControllers:viewControllers animated:YES];

1
@LukeRogers, bu benim için şu uyarıya neden oluyor: Beklenmedik bir durumda navigasyon geçişini bitirmek. Gezinme Çubuğu alt görünüm ağacı bozulabilir. Onu bastırmanın bir yolu var mı?
zaitsman

Bu çözümü kullanarak açılır bilgi penceresinin üzerine yazarsınız. Ve DetailView'de göstermek için kodunuz şöyle olmalıdır:if(indexPath.row == 0){UIViewController *newVC = [[UIViewController alloc] init];newVC = [self.storyboard instantiateViewControllerWithIdentifier:@"Item1VC"]; NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:[_detailViewController.navigationController viewControllers]]; [viewControllers removeLastObject];[viewControllers addObject:newVC]; [_detailViewController.navigationController setViewControllers:viewControllers animated:YES];}
LAOMUSIC ARTS

Aradığım şey.
JERC

9

Deneyimden, viewControllersdoğrudan UINavigationController özelliği ile uğraşmanız gerekecek . Bunun gibi bir şey çalışmalı:

MyEditViewController *mevc = [[MYEditViewController alloc] initWithGizmo: gizmo];

[[self retain] autorelease];
NSMutableArray *controllers = [[self.navigationController.viewControllers mutableCopy] autorelease];
[controllers removeLastObject];
self.navigationController.viewControllers = controllers;
[self.navigationController pushViewController:mevc animated: YES];

Not: Saklama / serbest bırakma işlemini, genellikle daha sağlam olduğu için bir tutma / serbest bırakma olarak değiştirdim - tutma / bırakma arasında bir istisna olursa, kendinizi sızdırırsınız, ancak otomatik sürüm bununla ilgilenir.


7

Çok çaba sarf ettikten (ve Kevin'den kodu değiştirdikten) sonra, sonunda yığından çıkan görüntü denetleyicisinde bunu nasıl yapacağımı buldum. Yaşadığım sorun, son nesneyi denetleyiciler dizisinden kaldırdıktan sonra self.navigationController'ın sıfır döndürmesiydi. Bunun nedeni, navigationController örnek yöntemindeki UIViewController belgelerinde bu satırdan kaynaklanıyordu "Yalnızca görünüm denetleyicisi kendi yığınında ise bir gezinme denetleyicisi döndürür."

Mevcut görünüm denetleyicisi yığından kaldırıldıktan sonra, navigationController yönteminin sıfır döndüreceğini düşünüyorum.

İşte çalışan ayarlanmış kod:

UINavigationController *navController = self.navigationController;
MyEditViewController *mevc = [[MYEditViewController alloc] initWithGizmo: gizmo];

NSMutableArray *controllers = [[self.navigationController.viewControllers mutableCopy] autorelease];
[controllers removeLastObject];
navController.viewControllers = controllers;
[navController pushViewController:mevc animated: YES];

Bu bana siyah bir bütün veriyor!
LAOMUSIC SANATLAR

4

Teşekkürler, tam da ihtiyacım olan buydu. Sayfanın kıvrılmasını sağlamak için bunu bir animasyona da koydum:

        MyEditViewController *mevc = [[MYEditViewController alloc] initWithGizmo: gizmo];

    UINavigationController *navController = self.navigationController;      
    [[self retain] autorelease];

    [UIView beginAnimations:nil context:NULL]; [UIView setAnimationDuration: 0.7];
    [UIView setAnimationTransition:<#UIViewAnimationTransitionCurlDown#> forView:navController.view cache:NO];

    [navController popViewControllerAnimated:NO];
    [navController pushViewController:mevc animated:NO];

    [UIView commitAnimations];

0.6 süresi hızlı, 3GS için iyi ve daha yeni, 0.8 hala 3G için biraz fazla hızlı.

Johan


Kodunuz tam olarak benim kullandığım şey, harika! Teşekkürler. Bir not: sayfa kıvrımlı geçişle, görüntünün altında beyaz bir yapaylık var (kim nedenini bilir) ama çevirmekle iyi çalıştı. Her neyse, bu güzel ve kompakt bir kod!
David H

3

PopToRootViewController tarafından başka bir görünüm denetleyicisini göstermek istiyorsanız, aşağıdakileri yapmanız gerekir:

         UIViewController *newVC = [[WelcomeScreenVC alloc] initWithNibName:@"WelcomeScreenVC" bundle:[NSBundle mainBundle]];
            NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:[[self navigationController] viewControllers]];
            [viewControllers removeAllObjects];
            [viewControllers addObject:newVC];
            [[self navigationController] setViewControllers:viewControllers animated:NO];

Şimdi, önceki yığınınızın tümü kaldırılacak ve gerekli rootViewController ile yeni yığın oluşturulacaktır.


1

Yakın zamanda benzer bir şey yapmak zorunda kaldım ve çözümümü Michaels'ın cevabına dayandırdım. Benim durumumda Gezinme Yığınından iki Görünüm Denetleyicisini kaldırmam ve ardından yeni bir Görüntü Denetleyicisini eklemem gerekiyordu. Aranıyor

[denetleyiciler removeLastObject];
iki kez, benim durumumda iyi çalıştı.

UINavigationController *navController = self.navigationController;

// retain ourselves so that the controller will still exist once it's popped off
[[self retain] autorelease];

searchViewController = [[SearchViewController alloc] init];    
NSMutableArray *controllers = [[self.navigationController.viewControllers mutableCopy] autorelease];

[controllers removeLastObject];
// In my case I want to go up two, then push one..
[controllers removeLastObject];
navController.viewControllers = controllers;

NSLog(@"controllers: %@",controllers);
controllers = nil;

[navController pushViewController:searchViewController animated: NO];


1

Bu UINavigationControllerörnek yöntemi işe yarayabilir ...

Belirtilen görünüm denetleyicisi, üst görünüm denetleyicisi olana kadar görünüm denetleyicilerini açar ve ardından ekranı güncelleştirir.

- (NSArray *)popToViewController:(UIViewController *)viewController animated:(BOOL)animated

1

ViewControllers dizisiyle doğrudan uğraşmayı gerektirmeyen başka bir yaklaşım. Denetleyicinin henüz açılıp açılmadığını kontrol edin, öyleyse itin.

TasksViewController *taskViewController = [[TasksViewController alloc] initWithNibName:nil bundle:nil];

if ([navigationController.viewControllers indexOfObject:taskViewController] == NSNotFound)
{
    [navigationController pushViewController:taskViewController animated:animated];
}
else
{
    [navigationController popToViewController:taskViewController animated:animated];
}

1
NSMutableArray *controllers = [self.navigationController.viewControllers mutableCopy];
    for(int i=0;i<controllers.count;i++){
       [controllers removeLastObject];
    }
 self.navigationController.viewControllers = controllers;

bu konsolda benim için bir uyarıya neden oluyor - Beklenmedik bir durumda gezinme geçişini tamamlama. Gezinme Çubuğu alt görünüm ağacı bozulabilir. Onu bastırmanın bir yolu var mı?
zaitsman

1

Bunu yapmanın en sevdiğim yolu, UINavigationController'da bir kategori kullanmaktır. Aşağıdakiler çalışmalıdır:

UINavigationController + Helpers.h #import

@interface UINavigationController (Helpers)

- (UIViewController*) replaceTopViewControllerWithViewController: (UIViewController*) controller;

@end

UINavigationController + Helpers.m
#import "UINavigationController + Helpers.h"

@implementation UINavigationController (Helpers)

- (UIViewController*) replaceTopViewControllerWithViewController: (UIViewController*) controller {
    UIViewController* topController = self.viewControllers.lastObject;
    [[topController retain] autorelease];
    UIViewController* poppedViewController = [self popViewControllerAnimated:NO];
    [self pushViewController:controller animated:NO];
    return poppedViewController;
}

@end

Ardından, görünüm denetleyicinizden, aşağıdaki gibi üst görünümü yenisiyle değiştirebilirsiniz:

[self.navigationController replaceTopViewControllerWithViewController: newController];

0

Gezinme yığınına eklediğiniz tüm görünüm denetleyicilerini size verdiğiniz gezinme görünümü denetleyicileri dizisiyle kontrol edebilirsiniz. Bu diziyi kullanarak, belirli bir görünüm denetleyicisine geri dönebilirsiniz.


0

Monotouch / xamarin IOS için:

UISplitViewController sınıfının içinde;

UINavigationController mainNav = this._navController; 
//List<UIViewController> controllers = mainNav.ViewControllers.ToList();
mainNav.ViewControllers = new UIViewController[] { }; 
mainNav.PushViewController(detail, true);//to have the animation

0

Alternatif olarak,

Sen kullanabilirsiniz categorykaçınmak self.navigationControllerolmak nilsonrapopViewControllerAnimated

sadece aç ve it, anlaşılması kolay, erişmeye gerek yok viewControllers...

ViewController'ınızda


0

Tam olarak cevap değil ama bazı senaryolarda yardımcı olabilir (örneğin benimki):

Görüntü denetleyicisi C'yi açmanız ve A (C'nin altındaki) yerine B'ye (yığın dışı) gitmeniz gerekirse, B'yi C'den önce itmek ve yığında 3'ü birden almak mümkündür. B itmesini görünmez tutarak ve yalnızca C veya C ve B'yi birlikte patlatmayı seçerek aynı etkiyi elde edebilirsiniz.

ilk problem A -> C (C'yi açıp B'yi yığının dışında göstermek istiyorum)

olası çözüm A -> B (görünmez olarak itildi) -> C (C'yi açtığımda, B'yi göstermeyi veya açmayı seçiyorum)


0

Animasyonu korumak için bu çözümü kullanıyorum.

[self.navigationController pushViewController:controller animated:YES];
NSMutableArray *newControllers = [NSMutableArray arrayWithArray:self.navigationController.viewControllers];
[newControllers removeObject:newControllers[newControllers.count - 2]];
[self.navigationController setViewControllers:newControllers];
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.