2009-10-12 16 views
16

Ho un UITableViewController che lancia un UIViewController e vorrei intercettare ogni volta che viene premuto il pulsante Indietro nel controller figlio, che è la classe che deriva da "UIViewController". Posso cambiare il titolo del pulsante Indietro, ma impostare i valori di azione target & quando si imposta backBarButtonItem sembra essere ignorato. Qual è un modo per ricevere una sorta di notifica che il pulsante Indietro è stato toccato?Come intercettare l'evento del pulsante Indietro

- (void)showDetailView 
{ 
    // How I'm creating & showing the detail controller 
    MyViewController *controller = [[MyViewController alloc] initWithNibName:@"MyDetailView" bundle:nil]; 

    UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@"Pages" 
          style:UIBarButtonItemStyleBordered 
          target:self          
          action:@selector(handleBack:)]; 

    self.navigationItem.backBarButtonItem = backButton; 
    [backButton release]; 

    [self.navigationController pushViewController:controller animated:animated]; 
    [controller release]; 

} 

- (void)handleBack:(id)sender 
{ 
    // not reaching here 
    NSLog(@"handleBack event reached"); 
} 
+1

Per le persone che cercano una soluzione efficiente iOS 5+: http: // stackoverflow.it/a/13370744/1072846 – Eric

risposta

1

È possibile rendere il proprio pulsante e posizionarlo come il leftBarButtonItem. Quindi chiama il metodo in cui puoi fare tutto e chiama lo [self.navigationController popViewController... da te

+1

"leftBarButtonItem" non mostrerà lo stesso stile di pulsante con il triangolo di aspetto laterale. Invece penso che il pulsante sarà quadrato. C'è un modo per far sembrare il tipico backbutton e intrappolare l'evento? –

+0

È possibile creare la propria immagine della freccia sinistra se si conosce la larghezza del testo del pulsante, oppure è possibile crearlo a livello di programmazione, imitando ciò che fa Apple. – coneybeare

18

È possibile implementare il metodo viewWillDisappear di UIViewController. Questo viene chiamato quando il controller sta per andare via (o perché un altro è stato inserito nello stack del controller di navigazione o perché è stato premuto il pulsante "indietro").

Per determinare se la vista sta scomparendo a causa del pulsante indietro viene premuto, è possibile utilizzare una bandiera personalizzata impostata ovunque si preme un nuovo controller sul controller di navigazione, come mostrato di seguito

- (void)viewWillDisappear:(BOOL)animated { 
    [super viewWillDisappear:animated]; 
    if (viewPushed) { 
     viewPushed = NO; // Flag indicates that view disappeared because we pushed another controller onto the navigation controller, we acknowledge it here 
    } else { 
     // Here, you know that back button was pressed 
    } 
} 

E ovunque si preme un nuovo controller della vista, si dovrà ricordare di impostare anche quella bandiera ...

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 
    ... 
    viewPushed = YES; 
    [self.navigationController pushViewController:myNewController animated:YES]; 
    ... 
} 
+0

Come puoi sapere che la vista non è scomparsa perché un altro pulsante ha richiamato una vista secondaria? Voglio sapere solo quando viene premuto il pulsante "Indietro". –

+0

In casi come questo, ho impostato un flag in didSelectRowAtIndexPath: (dove di solito spinga un nuovo controller sul controller di navigazione). viewWillDisappear può quindi controllare quel flag e dedurre se il pulsante back è stato premuto o meno –

+0

Che ancora non risolve il problema che Justin ha sottolineato; Con la tua bandiera saprai come è nata la vista, ma ciò non significa che sia l'unico modo in cui scomparirà. – kbanman

17

E 'stato un po' che questo è stato chiesto, ma ho solo cercato di fare da solo. Ho usato una soluzione simile a Zoran di, tuttavia invece di usare una bandiera ho fatto questo:

- (void)viewWillDisappear: (BOOL)animated 
{ 
    [super viewWillDisappear: animated]; 
    if (![[self.navigationController viewControllers] containsObject: self]) 
    { 
     // the view has been removed from the navigation stack, back is probably the cause 
     // this will be slow with a large stack however. 
    } 
} 

penso che bypassa i problemi con le bandiere e IMO è più pulita, ma non come efficiente (se ci sono un sacco di articoli su il controller di navigazione).

+6

Potrebbe essere possibile usare '[self.navigationController.viewControllers indexOfObjectIdenticalTo: self]! = NSNotFound' invece di' containsObject', che confronta solo l'indirizzo del puntatore. –

+0

Controllato questo: Funziona. –

+1

Se il tuo controller è contenuto in un altro contenitore, dovrai confrontare tramite: "indexOfObjectIdenticalTo: self.parentViewController", a parte questo, funziona. – marmor

0
{ 
    UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@"back" 
                    style:UIBarButtonItemStyleBordered 
                    target:self                    
                    action:@selector(handleBack:)]; 
    self.navigationItem.leftBarButtonItem = backButton; 
    [backButton release]; 
    [self filldata]; 
    [super viewDidLoad]; 
} 

basta sostituire backBarButtonItem con leftBarButtonItem

8

uso questo codice:

- (void) viewWillDisappear:(BOOL)animated { 

    if ([self.navigationController.viewControllers indexOfObject:self] == NSNotFound) 
    { 
     // your view controller already out of the stack, it meens user pressed Back button 
    } 
} 

Ma ciò non è vero quando l'utente preme il tasto tab bar e si apre per sradicare vista controllore in uno scatto. Per questa situazione utilizzare questo:

[[NSNotificationCenter defaultCenter] addObserver:self 
              selector:@selector(viewControllerChange:) 
               name:@"UINavigationControllerWillShowViewControllerNotification" 
               object:self.navigationController]; 


- (void) viewControllerChange:(NSNotification*)notification { 

    NSDictionary* userInfo = [notification userInfo]; 

    if ([[userInfo objectForKey:@"UINavigationControllerNextVisibleViewController"] isKindOfClass:[<YourRootControllerClass> class]]) 
    { 
     // do your staff here 
    } 
} 

Non dimenticare poi:

[[NSNotificationCenter defaultCenter] removeObserver:self 
                name:@"UINavigationControllerWillShowViewControllerNotification" 
               object:self.navigationController]; 
12

A mio parere la migliore soluzione.

- (void)didMoveToParentViewController:(UIViewController *)parent 
{ 
    if (![parent isEqual:self.parentViewController]) { 
     NSLog(@"Back pressed"); 
    } 
} 

ma funziona solo con iOS5 +

+0

Questa è la soluzione migliore, poiché è più autosufficiente. – canhazbits

+0

dove scrivere questo – NaXir

-2

Basta usare viewDidDisappear invece. Sarà perfettamente chiamato in qualsiasi scenario.

Basiamo la gestione del ciclo di vita su viewDidAppear e viewDidDappari. Se conosci Android: entrambi sono paragonabili ai metodi onResume e onPause. Ma c'è una differenza quando si tratta di bloccare lo schermo o premere il tasto home su iOS.

Problemi correlati