2010-01-22 25 views
23

Sto cercando di individuare il modo "migliore" per utilizzare un UISegmentedControl per un'applicazione iPhone. Ho letto alcuni post qui su StackOverflow e ho visto alcune idee di alcune persone, ma non riesco a trovare il modo migliore per farlo. I posti mi riferisco sono:UISegmentedControl Best Practice

Changing Views from UISegmentedControl e How do I use a UISegmentedControl to switch views?

Sembrerebbe che le opzioni sono:

  • aggiungere tutti i punti di vista in IB e lay out in cima l'altro poi mostrare/nasconderli
  • creare ognuno dei subviews separatamente in IB, quindi creare un contenitore in vista principale per popolare con la visualizzazione secondaria che è necessario
  • Impostare uno molto alto o davvero ampia UIView e animarlo sinistra/destra o su/giù a seconda del segmento selezionato
  • Utilizzare un UITabBarController per scambiare le subviews - sembra sciocco
  • Per le tabelle, ricaricare tavola e in cellForRowAtIndex e compilare la tabella da diverse fonti di dati o sezioni in base all'opzione segmento selezionato (non è il caso per la mia app)

Quindi, quale approccio è meglio per gli approcci visualizzazione secondaria/non-tavolo? Qual è il modo più semplice da implementare? Potresti condividere qualche codice di esempio con l'approccio?

Grazie!

risposta

11

Vorrei andare con la seconda opzione che hai menzionato, creando le sottoview in IB e scambiandole dentro e fuori da una vista principale. Questa sarebbe una buona opportunità per utilizzare UIViewController, non classificato: nella configurazione iniziale, creare un controller usando -initWithNibName:bundle: (dove il primo parametro è il nome del NIB contenente la sottoview individuale e il secondo parametro è nil) e aggiungere il suo view come una sottoview della tua vista principale se necessario. Ciò contribuirà a mantenere basso l'ingombro di memoria: il comportamento predefinito di un UIViewController quando si riceve un avviso di memoria è di rilasciare la sua vista se non ha superview. Finché rimuovi le viste nascoste dalla gerarchia delle viste, puoi tenere i controller in memoria e non preoccuparti di rilasciare nulla.

(modificati in risposta al commento :)

Non è necessario creare una sottoclasse UIViewController, ma si ha bisogno XIBs separate per ogni vista. Inoltre non è necessario aggiungere nulla alla vista contenente in IB.

variabili di istanza, nell'interfaccia di qualsiasi classe sta gestendo tutto questo:

UIViewController *controllerOne; 
UIViewController *controllerTwo; 

UIViewController *currentController; 

IBOutlet UIView *theContainerView; 

nel vostro setup (-applicationDidFinishLaunching: o altro)

controllerOne = [[UIViewController alloc] initWithNibName:@"MyFirstView" bundle:nil]; 
controllerTwo = [[UIViewController alloc] initWithNibName:@"MySecondView" bundle:nil]; 

Per passare a un controller:

- (void)switchToController:(UIViewController *)newCtl 
{ 
     if(newCtl == currentController) 
      return; 
     if([currentController isViewLoaded]) 
      [currentController.view removeFromSuperview]; 

     if(newCtl != nil) 
      [theContainerView addSubview:newCtl.view]; 

     currentController = newCtl; 
} 

Quindi basta chiamarlo con, ad es.,

[self switchToController:controllerOne]; 
+0

Giusto per chiarire ... Stai dicendo di creare un .h UIViewController separata, .m, e .xib in IB per ogni sottoview, istanzia uno di loro nel viewDidLoad della vista "contenente", aggiungi un UIView in IB alla vista contenente, poi fai cosa ?? –

19

Mi sono imbattuto in questo requisito anche in un'applicazione iPad.

La soluzione sono venuto a era quello di creare controller di vista specializzati per ogni stile di vista per gestire la logica di business relativo a tali viste (es. In materia di ogni segmento), e programatically aggiungere/rimuovere loro come subviews ad un 'gestione' del controller in risposta al segmento selezionato modifiche dell'indice.

Per fare ciò, è necessario creare una sottoclasse UIViewController aggiuntiva che gestisca le modifiche di UISegmentedControl e aggiunge/rimuove le visualizzazioni secondarie.

Il seguente codice fa tutto questo, anche prendersi cura di alcune avvertenze/extra:

  • viewWillAppear/viewWillDisappear/etc, non sono invitato le subviews automaticamente, e hanno bisogno di essere detto attraverso il controller 'gestione'
  • viewWillAppear/viewWillDisappear/etc, non sono chiamati a 'gestire' regolatore quando è all'interno di un controller di navigazione, quindi il controller di navigazione delegato
  • Se vuoi spingere su una pila di navigazione dall'interno di un sottoview del segmento, è necessario richiamare la vista 'gestione' per farlo, poiché la sottoview è stata creata al di fuori della gerarchia di navigazione e non avrà un riferimento al controller di navigazione .
  • Se utilizzato in uno scenario di controller di navigazione, il pulsante Indietro è impostato automaticamente sul nome del segmento.

Interfaccia:

@interface SegmentManagingViewController : UIViewController <UINavigationControllerDelegate> { 
    UISegmentedControl * segmentedControl; 
    UIViewController  * activeViewController; 
    NSArray    * segmentedViewControllers; 
} 

@property (nonatomic, retain) IBOutlet UISegmentedControl * segmentedControl; 
@property (nonatomic, retain) UIViewController   * activeViewController; 
@property (nonatomic, retain) NSArray      * segmentedViewControllers; 

@end 

Implementazione:

@interface SegmentManagingViewController() 
- (void)didChangeSegmentControl:(UISegmentedControl *)control; 
@end 

@implementation SegmentManagingViewController 

@synthesize segmentedControl, activeViewController, segmentedViewControllers; 

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    UIViewController * controller1 = [[MyViewController1 alloc] initWithParentViewController:self]; 
    UIViewController * controller2 = [[MyViewController2 alloc] initWithParentViewController:self]; 
    UIViewController * controller3 = [[MyViewController3 alloc] initWithParentViewController:self]; 

    self.segmentedViewControllers = [NSArray arrayWithObjects:controller1, controller2, controller3, nil]; 
    [controller1 release]; 
    [controller2 release]; 
    [controller3 release]; 

    self.navigationItem.titleView = self.segmentedControl = 
    [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:@"Seg 1", @"Seg 2", @"Seg 3", nil]]; 
    self.segmentedControl.selectedSegmentIndex = 0; 
    self.segmentedControl.segmentedControlStyle = UISegmentedControlStyleBar; 

    [self.segmentedControl addTarget:self action:@selector(didChangeSegmentControl:) forControlEvents:UIControlEventValueChanged]; 

    [self didChangeSegmentControl:self.segmentedControl]; // kick everything off 
} 

- (void)viewWillAppear:(BOOL)animated { 
    [super viewWillAppear:animated]; 
    [self.activeViewController viewWillAppear:animated]; 
} 

- (void)viewDidAppear:(BOOL)animated { 
    [super viewDidAppear:animated]; 
    [self.activeViewController viewDidAppear:animated]; 
} 

- (void)viewWillDisappear:(BOOL)animated { 
    [super viewWillDisappear:animated]; 
    [self.activeViewController viewWillDisappear:animated]; 
} 

- (void)viewDidDisappear:(BOOL)animated { 
    [super viewDidDisappear:animated]; 
    [self.activeViewController viewDidDisappear:animated]; 
} 

#pragma mark - 
#pragma mark UINavigationControllerDelegate control 

// Required to ensure we call viewDidAppear/viewWillAppear on ourselves (and the active view controller) 
// inside of a navigation stack, since viewDidAppear/willAppear insn't invoked automatically. Without this 
// selected table views don't know when to de-highlight the selected row. 

- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated { 
    [viewController viewDidAppear:animated]; 
} 

- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated { 
    [viewController viewWillAppear:animated]; 
} 

#pragma mark - 
#pragma mark Segment control 

- (void)didChangeSegmentControl:(UISegmentedControl *)control { 
    if (self.activeViewController) { 
     [self.activeViewController viewWillDisappear:NO]; 
     [self.activeViewController.view removeFromSuperview]; 
     [self.activeViewController viewDidDisappear:NO]; 
    } 

    self.activeViewController = [self.segmentedViewControllers objectAtIndex:control.selectedSegmentIndex]; 

    [self.activeViewController viewWillAppear:NO]; 
    [self.view addSubview:self.activeViewController.view]; 
    [self.activeViewController viewDidAppear:NO]; 

    NSString * segmentTitle = [control titleForSegmentAtIndex:control.selectedSegmentIndex]; 
    self.navigationItem.backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:segmentTitle style:UIBarButtonItemStylePlain target:nil action:nil]; 
} 

#pragma mark - 
#pragma mark Memory management 

- (void)dealloc { 
    self.segmentedControl = nil; 
    self.segmentedViewControllers = nil; 
    self.activeViewController = nil; 
    [super dealloc]; 
} 

@end 

Spero che questo aiuti.

+1

Votato! C'è una piccola perdita di memoria in -didChangeSegmentedControl: metodo. L'ultima istruzione dovrebbe essere: self.navigationItem.backBarButtonItem = [[[UIBarButtonItem alloc]] initWithTitle: segmentTitle style: UIBarButtonItemStylePlain target: nil action: nil] autorelease]; Una perdita di memoria simile si trova in viewDidLoad: self.navigationItem.titleView = self.segmentedControl = [[[UISegmentedControl alloc]] initWithItems: [NSArray arrayWithObjects: @ "Seg 1", @ "Seg 2", @ "Seg 3", nil ]] autorelease]; – Mustafa

+0

Aggiunta di un collegamento a un ulteriore aggiornamento che ho pubblicato per quanto riguarda questo modello - utilizzando un UINavigationController anziché un controller di visualizzazione 'contenitore'. http: // redartisan.com/2010/6/27/uisegmented-control-view-switching-revisited – crafterm

+0

Per qualche motivo quando lo uso su un iPad, la sezione dei dettagli non viene ridimensionata correttamente, è come se le viste fossero disegnate in pieno ritratto iPad. – Convolution