Implementering av Container Containment - Sliding Menu Controller

I denne opplæringen implementerer vi en minimalistisk versjon av brukergrensesnittet Facebook / Path-stil. Målet vil være å forstå hvordan du bruker visningskontrollenes inneslutning for å implementere tilpasset strøm i appen din.


Teoretisk oversikt

Vis kontroller er en viktig del av et hvilket som helst iOS-program, uansett hvor lite, stort, enkelt eller komplekst. De gir "limlogikken" mellom datamodellen til appen din og brukergrensesnittet.

I bred grad er det to typer visningskontroller:

  • Innholdsvisningskontrollere: Disse er ansvarlige for visning og håndtering av synlig innhold.
  • Containerkontrollere: Disse administrerer innholdsvisningskontrollere, og de er ansvarlige for den generelle strukturen og strømmen av appen.

En containerkontroller kan ha noen synlig komponent av seg selv, men fungerer i utgangspunktet som vert for innholdsvisningskontrollere. Containerkontrollere tjener til å "trafikkere" kommendene og gåttene til innholdsvisningskontrollere.

UINavigationController, UITabBarController og UIPageViewController er eksempler på beholdervisningskontrollere som sender med iOS SDK. Vurder hvordan de tre er forskjellige når det gjelder applikasjonsflytene som de gir opphav til. Navigasjonskontrolleren er flott for en applikasjon med drill-down-typen, der valget brukeren gjør på en skjerm, påvirker hvilke valg han presenteres på neste skjermbilde. Kontrollpanelet for kontrollpanelet er flott for apper med uavhengige funksjoner, slik at du enkelt kan bytte ved å trykke på en knappeknapp. Endelig presenterer sidevisningscontrolleren en bokmetafor, slik at brukeren kan bla frem og tilbake mellom sider med innhold.

Den viktigste tingen å huske på her er at en faktisk skjermfull av innhold som presenteres gjennom noen av disse beholdervisningskontrollene selv må styres, både når det gjelder dataene den kommer fra (modellen) og skjermpresentasjonen (visningen), som igjen ville være jobben til en visningskontroller. Nå snakker vi om innholdsvisningskontrollere. I enkelte apper, spesielt på iPad fordi den større skjermen gjør det mulig å vise flere innhold på en gang, kan det hende at ulike visninger på skjermen kanskje må administreres uavhengig. Dette krever flere visningskontrollere på skjermen samtidig. Alt dette innebærer at visningskontrollerne i en godt designet app skal implementeres på en hierarkisk måte med både container- og innholdsvisningskontrollere som spiller sine respektive roller.

Før iOS 5 var det ikke noe middel til å erklære et hierarkisk (dvs. foreldre-barn) forhold mellom to visningskontrollere og derfor ikke en "riktig" måte å implementere en egendefinert applikasjonsflyt på. Man måtte enten gjøre med de innebygde typene, eller gjøre det på en tilfeldig måte, som i utgangspunktet besto av stikkende visninger administrert av en visningskontroller i visningshierarkiet av visningen som administreres av en annen visningsregulator. Dette ville skape uoverensstemmelser. For eksempel vil en visning ende opp med å være i visningshierarkiet til to kontrollere uten at noen av disse kontrollerne anerkjenner den andre, noe som noen ganger fører til merkelig oppførsel. Inneslutning ble introdusert i IOS 5 og raffinert litt i IOS 6, og det tillater at forestillingen om foreldre og barnesyn kontrollører i et hierarki blir formalisert. I hovedsak krever korrekt innstilling av kontrollkontrollen at hvis visning B er et undervisning (barn) til visning A, og hvis de ikke er under ledelse av samme visningsregulator, må Bs visningsstyrer gjøres til A's view-kontrollørens barn.

Du kan spørre om det er noen konkret fordel som tilbys ved å se kontrollenhetens inneslutning utover fordelen av det hierarkiske designet vi diskuterte. Svaret er ja. Husk at når en visningscontroller kommer på skjermen eller går bort, kan det hende at vi må sette opp eller rive ned ressurser, rydde opp, hente eller lagre informasjon fra / til filsystemet. Vi vet alle om utseende tilbakekallinger. Ved å forklare foreldre-barn-forholdet, sørger vi for at foreldrekontrolleren sender videre tilbakemeldinger til sine barn når en kommer på eller går av skjermen. Rotasjons tilbakeringinger må også videresendes. Når orienteringen endres, må alle visningsstyrerne på skjermen vite slik at de kan tilpasse innholdet på riktig måte.

Hva betyr alt dette, når det gjelder kode? Se kontroller har en NSArray eiendom kalt childViewControllers og vårt ansvar omfatter å legge til og fjerne barnvisningskontrollere til og fra denne gruppen i foreldrene ved å ringe til rette metoder. Disse metodene inkluderer addChildViewController (oppfordret til foreldrene) og removeFromParentViewController (kalt barnet) når vi prøver å gjøre eller bryte foreldre-barn forholdet. Det er også et par meldingsmeldinger som sendes til barnevisekontrolleren ved starten og slutten av tilleggs / fjerningsprosessen. Disse er willMoveToParentViewController: og didMoveToParentViewController:, sendt med riktig foreldrekontrollør som argument. Argumentet er nil, hvis barnet blir fjernet. Som vi ser, blir en av disse meldingene sendt automatisk til oss mens den andre har ansvaret for å sende. Dette vil avhenge av om vi legger til eller fjerner barnet. Vi vil studere den nøyaktige sekvensen snart når vi implementerer ting i kode. Barnet kontrolleren kan svare på disse varslene ved å implementere de tilsvarende metodene hvis den trenger å gjøre noe under forberedelsen av disse hendelsene.

Vi må også legge til / fjerne visninger som er tilknyttet barnvisningen til foreldrenes hierarki, ved hjelp av metoder som addSubview: eller removeFromSuperview), inkludert å utføre noen medfølgende animasjoner. Det er en praktisk metode (-) transitionFromViewController: toViewController Varighet alternativer: animasjoner: ferdigstillelse: som gir oss mulighet til å strømlinjeforme prosessen med å bytte barnvisningskontrollere på skjermen med animasjoner. Vi ser på de nøyaktige detaljene når vi skriver koden - som er neste!


1. Opprette et nytt prosjekt

Opprett en ny iOS-app i Xcode basert på "Tom søknad"mal. Gjør det til en iOS-app med ARC-aktivert. Ring det VCContainmentTut.

Opprette et nytt prosjekt

2. Implementere Container View Controller

Opprett en ny klasse som heter RootController. Gjør det til en UIViewController underklasse. Kontroller at eventuelle avkrysningsbokser er deaktivert. Dette blir vår undervisningsgruppe for kontroller av kontroller.


Erstatt koden i RootViewController.h med følgende.

 #importere  @interface RootController: UIViewController // (1) - (id) initWithViewControllers: (NSArray *) viewControllers andMenuTitles: (NSArray *) titler; // (2) @end

Vår containerkontroller har en tabellvisning som fungerer som vår meny, og ved å trykke på en hvilken som helst celle, erstatter den nåværende synlige kontrolleren av den som er valgt gjennom brukerens trykk.

Henvisning til punktene i koden,

  1. Vår rotorstyrer dobler som menyens (dvs. tabellvisningsens) delegat og datakilde.
  2. Vi tilbyr en ekstremt enkel API (så langt som brukeren av våre containerklasser) består av en initialiserer som tar en liste over visningskontrollere som vår rotorstyrer skal inneholde, og en liste over strenger som representerer titlene for hver visningskontroller i Meny. Dette er slik at vi kan konsentrere oss om det grunnleggende. Når du forstår disse, kan du gjøre API-en så passbar som du vil.

La oss ta en titt fremover for å se hva vårt ferdige produkt vil se ut slik at du har et mentalt bilde for å knytte implementeringen med.


Det vil bidra til å innse at vår containervisningskontroller er ganske lik en tabulator. Hvert element i menyen tilsvarer en uavhengig visningskontroller. Forskjellen mellom vår "skyvemeny"kontrolleren og fanen er visuelt for det meste. Uttrykket"skyvemeny"er litt misvisende fordi det faktisk er innholdsvisningskontrollen som glir for å skjule eller avsløre menyen under.

Fortsett til implementeringen, erstatt all koden i RootController.m med følgende kode.

 #define kExposedWidth 200.0 #define kMenuCellID @ "MenuCell" #import "RootController.h" @interface RootController () @property (ikkeatomisk, sterk) UITableView * -menyen; @property (nonatomic, strong) NSArray * viewControllers; @property (nonatomic, strong) NSArray * menyTitler; @property (ikkeatomisk, tilordne) NSInteger indexOfVisibleController; @property (nonatomic, assign) BOOL erMenuVisible; @end @implementation RootController - (id) initWithViewControllers: (NSArray *) viewControllers andMenuTitles: (NSArray *) menyTitler hvis (selv = [super init]) NSAssert (self.viewControllers.count == self.menuTitles.count, @ "Det må være en og eneste meny tittel som tilsvarer hver visningskontroller!"); // (1) NSMutableArray * tempVCs = [NSMutableArray arrayWithCapacity: viewControllers.count]; self.menuTitles = [menuTitles copy]; for (UIViewController * vc i viewControllers) // (2) if (! [vc isMemberOfClass: [UINavigationController class]]) [tempVCs addObject: [[UINavigationController alloker] initWithRootViewController: vc]];  ellers [tempVCs addObject: vc]; UIBarButtonItem * revealMenuBarButtonItem = [[UIBarButtonItem alloc] initWithTitle: @ "Meny" stil: UIBarButtonItemStylePlain mål: selvhandling: @selector (toggleMenuVisibility :)]; // (3) UIViewController * topVC = ((UINavigationController *) tempVCs.lastObject) .topViewController; topVC.navigationItem.leftBarButtonItems = [@ [revealMenuBarButtonItem] arrayByAddingObjectsFromArray: topVC.navigationItem.leftBarButtonItems];  self.viewControllers = [tempVCs copy]; self.menu = [[UITableView alloc] init]; // (4) self.menu.delegate = self; self.menu.dataSource = self;  returner selv;  - (void) viewDidLoad [super viewDidLoad]; [self.menu registerClass: [UITableViewCell class] forCellReuseIdentifier: kMenuCellID]; self.menu.frame = self.view.bounds; [self.view addSubview: self.menu]; self.indexOfVisibleController = 0; UIViewController * visibleViewController = self.viewControllers [0]; visibleViewController.view.frame = [self offScreenFrame]; [self addChildViewController: visibleViewController]; // (5) [self.view addSubview: visibleViewController.view]; // (6) self.isMenuVisible = JA; [selvjusteringContentFrameAccordingToMenuVisibility]; // (7) [self.viewControllers [0] didMoveToParentViewController: selv]; // (8) - (void) toggleMenuVisibility: (id) sender // (9) self.isMenuVisible =! Self.isMenuVisible; [selvjusteringContentFrameAccordingToMenuVisibility];  - (void) adjustContentFrameAccordingToMenuVisibility // (10) UIViewController * visibleViewController = self.viewControllers [self.indexOfVisibleController]; CGSize size = visibleViewController.view.frame.size; hvis (self.isMenuVisible) [UIView animateWithDuration: 0.5 animasjoner: ^ visibleViewController.view.frame = CGRectMake (kExposedWidth, 0, size.width, size.height); ];  ellers [UIView animateWithDuration: 0.5 animasjoner: ^ visibleViewController.view.frame = CGRectMake (0, 0, size.width, size.height); ];  - (void) replaceVisibleViewControllerWithViewControllerAtIndex: (NSInteger) indeks // (11) if (index == self.indexOfVisibleController) returnere; UIViewController * incomingViewController = self.viewControllers [indeks]; incomingViewController.view.frame = [self offScreenFrame]; UIViewController * outgoingViewController = self.viewControllers [self.indexOfVisibleController]; CGRect visibleFrame = self.view.bounds; [outgoingViewController willMoveToParentViewController: null]; // (12) [self addChildViewController: incomingViewController]; // (13) [[UIApplication sharedApplication] beginIgnoringInteractionEvents]; // (14) [self transitionFromViewController: outgoingViewController // (15) toViewController: incomingViewController varighet: 0.5 alternativer: 0 animasjoner: ^ outgoingViewController.view.frame = [self offScreenFrame];  fullføring: ^ (BOOL ferdig) [UIView animateWithDuration: 0.5 animasjoner: ^ outgoingViewController.view removeFromSuperview]; [self.view addSubview: incomingViewController.view]; incomingViewController.view.frame = visibleFrame; [[UIApplication sharedApplication] endIgnoringInteractionEvents]; // (16)]; [innkommendeViewController didMoveToParentViewController: selv]; // (17) [outgoingViewController removeFromParentViewController]; // (18) self.isMenuVisible = NO; self.indexOfVisibleController = index; ];  // (19): - (NSInteger) numberOfSectionsInTableView: (UITableView *) tableView return 1;  - (NSInteger) tableView: (UITableView *) tableView numberOfRowsInSection: (NSInteger) seksjonen return self.menuTitles.count;  - (UITableViewCell *) tableView: (UITableView *) tableView cellForRowAtIndexPath: (NSIndexPath *) indexPath UITableViewCell * celle = [tableView dequeueReusableCellWithIdentifier: kMenuCellID]; cell.textLabel.text = self.menuTitles [indexPath.row]; returcelle;  - (void) tableView: (UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *) indexPath [self replaceVisibleViewControllerWithViewControllerAtIndex: indexPath.row];  - (CGRect) offScreenFrame return CGRectMake (self.view.bounds.size.width, 0, self.view.bounds.size.width, self.view.bounds.size.height);  @slutt

Nå for en forklaring av koden. Delene som jeg har uthevet for vektlegging, er spesielt relevante for innlemmingen.

  1. For det første gjør initieringen en enkel kontroll for å sikre at hver visningskontroller har fått en menytittel. Vi har ikke gjort noen type kontroller for å sikre at hver av de to arrays som sendes til initialisatoren inneholder riktig type objekter, UIViewController og NSString typer henholdsvis. Du kan vurdere å gjøre det. Vær oppmerksom på at vi opprettholder arrayer for hver av disse, kalt viewControllers, og menuTitles.
  2. Vi vil at det skal være en knapp som, når den er tappet, viser eller skjuler menyen. Min enkle løsning på hvor knappen skulle være, var å sette alle visningskontroller som vi mottok fra initialisatoren inne i en navigasjonsregulator. Dette gir oss en gratis navigasjonsbjelke som en knapp kan legges til, med mindre den kontrollerte kontrollen allerede var en navigasjonsstyring, i så fall gjør vi ikke noe ekstra.
  3. Vi lager et barknappelement som utløser menyens utseende eller gjemmer seg ved å skyve visningsregulatoren som er synlig. Vi legger det til navigasjonslinjen ved å flytte eksisterende knapper på navigasjonsfeltet til høyre. Vi gjør dette fordi kontrollpanelet for tilleggsvisning er allerede en navigasjonsregulator med eksisterende knapper.
  4. Vi ordner vår meny som en tabellvisning og tilordner rotkontrollen selv som delegat og datakilde.
  5. I viewDidLoad, Etter at du har konfigurert og lagt til menybordvisningen til rotorkontrollørens visning, innleder vi inn i vår app den første visningskontrolleren i viewControllers matrise. Ved å sende addChildViewController: melding til vår rotorkontroller, utfører vi vårt første inneslutningsrelaterte ansvar. Du bør vite at dette fører til meldingen willMoveToParentViewController: å bli kalt barnets kontroller.
  6. Vær oppmerksom på at vi eksplisitt må legge til barnets kontrollerens syn på foreldrenes visningshierarki!
  7. Vi stiller inn menyen først og fremst og kaller en metode som justerer visningen av synlig innholdsvisningskontrollen, og tar hensyn til menyens synlighet. Vi vil se nærmere på denne metodenes detaljer snart.
  8. Når barnet ser kontrolleren sin utsikt sitter komfortabelt i foreldrenes synshierarki, Vi sender meldingen didMoveToParentViewController til den ekstra barnkontrolleren, med selv-, RootController-forekomsten, som argumentet. I vår barns kontroller kan vi implementere denne metoden hvis vi trenger det.
  9. En enkel metode som er koblet til menylinjeknappens handling som skifter menyens synlighet ved å justere overleggsvisningskontrollens syn på riktig måte.
  10. Som navnet indikerer, adjustContentFrameAccordingToMenuVisibility lar oss justere innholdsvisningskontrollens ramme for å fortelle oss om menyen er skjult eller ikke. Hvis ja, overlapper det tilsynet. Ellers skiftes det til høyre ved kExposedWidth. Jeg har satt det til 200 poeng.
  11. Igjen, så tydelig angitt av navnet, replaceVisibleViewControllerWithViewControllerAtIndex tillater oss å bytte ut se kontroller og tilhørende visninger fra hierarkiet. For å trekke av animasjonen vår, som består av å skyve den erstattede visningskontrollen til skjermen til høyre og deretter ta inn erstatningsenheten fra samme sted, definerer vi noen rektangulære rammer.
  12. willMoveToParentViewController med nil. Når vi har fullført dette trinnet, vil denne visningskontrolleren slutte å motta utseende og rotasjonsoppringninger fra foreldrene. Dette gir mening fordi det ikke lenger er en aktiv del av appen.
  13. Vi legger til den innkommende visningskontrollen som et barn til rotkontrolleren, likt det vi gjorde i begynnelsen.
  14. Vi begynner å ignorere hendelser for brukerinteraksjon for å la oversikten over kontrolleren veksle over det.
  15. Denne bekvemmelighetsmetoden tillater oss å animere fjerningen av den utgående kontrolleren og ankomsten av den innkommende mens den utfører den nødvendige rekkefølgen av hendelser som er involvert i tilleggs-og fjerningsprosessen for barnevisekontrollen. Vi animerer den utgående VC-visningen for å skyve offscreen til høyre, og etter at animasjonen er fullført, fjerner vi den fra visningshierarkiet. Vi animerer deretter innkommende kontroller for å skyve inn fra samme sted avskjerm og okkupere stedet som tidligere ble tatt opp av den utgående kontrollerens visning.
  16. Vi aktiverer appen vår for å godta innkommende samspillingshendelser, siden vår kontroll av byttekontrollen er fullført.
  17. Vi informerer innkommende kontroller om at den er flyttet til containerkontrolleren ved å sende den til didMoveToParentViewController melding med selv- som argumentet.
  18. Vi fjerner den utgående kontrolleren fra containerkontrolleren ved å sende den til removeFromParentViewController budskap. Du burde vite det didMoveToParentViewController: med nil som et argument blir sendt for deg.
  19. Vi implementerer menytabellvisningens delegerte og datakildeprotokollmetoder, som er ganske enkle. Dette inkluderer å utløse visningsstyringsbyttetrinnet (11) når et nytt elements celle er tappet i menyen via -Tableview: didSelectRowAtIndexPath: metode.

Du har kanskje funnet sekvensen av samtaler som er relatert til kontrollerens inneslutning, litt forvirrende. Det hjelper å oppsummere.

    Når du legger til en barnevise-kontroller til en forelder:
  • Anrop addChildViewController: på foreldrene med barnet som argumentet. Dette forårsaker meldingen willMoveToParentViewController: å bli sendt til barnet med foreldrene som argumentet.
  • Legg til barnets visning som et undervisning av foreldrenes visning.
  • Utelat ring didMoveToParentViewController: på barnet med foreldrene som argumentet.
    Når du fjerner en barnevisekontroll fra sin overordnede:
  • Anrop willMoveToParentViewController: på barnet med nil som argumentet.
  • Fjern barnets visning fra overvåkingen.
  • Sende removeFromParentViewController til barnet. Årsaken til meldingen didMoveToParentViewController med nil som argumentet som skal sendes til barnet på dine vegne.

3. Testing

La oss teste de forskjellige typer visningskontrollere som er lagt til vår rotkontroll! Opprett en ny underklasse av UIViewController kalt ViewController, holde eventuelle valg ukontrollert.

Bytt koden i ViewController.m med følgende kode.

 #import "ViewController.h" @interface ViewController () @end @implementation ViewController - (void) willMoveToParentViewController: (UIViewController *) forelder NSLog (@ "% @ (% p) -% @", NSStringFromClass ([selvklasse] ), selv, NSStringFromSelector (_cmd));  - (void) didMoveToParentViewController: (UIViewController *) forelder NSLog (@ "% @ (% p) -% @", NSStringFromClass ([selvklasse)), selv, NSStringFromSelector (_cmd));  - (void) viewWillAppear: (BOOL) animert [super viewWillAppear: animated]; NSLog (@ "% @ (% p) -% @", NSStringFromClass ([selvklass]), selv, NSStringFromSelector (_cmd));  - (void) viewDidAppear: (BOOL) animert [super viewDidAppear: animated]; NSLog (@ "% @ (% p) -% @", NSStringFromClass ([selvklass]), selv, NSStringFromSelector (_cmd));  - (void) willRotateToInterfaceOrientation: (UIInterfaceOrientation) toInterfaceOrientation varighet: (NSTimeInterval) varighet [super willRotateToInterfaceOrientation: toInterfaceOrientation varighet: varighet]; NSLog (@ "% @ (% p) -% @", NSStringFromClass ([selvklass]), selv, NSStringFromSelector (_cmd));  - (void) didRotateFromInterfaceOrientation: (UIInterfaceOrientation) fromInterfaceOrientation [super didRotateFromInterfaceOrientation: fromInterfaceOrientation]; NSLog (@ "% @ (% p) -% @", NSStringFromClass ([selvklass]), selv, NSStringFromSelector (_cmd));  @slutt

Det er ikke noe spesielt med vår visningskontroller selv, bortsett fra at vi har overstyrt de ulike tilbakeringingene, slik at vi kan logge dem når vår ViewController forekomst blir et barn til vår rotkontroller og et utseende eller rotasjonshendelse forekommer.

I all tidligere kode, _cmd refererer til väljeren som svarer til metoden som utførelsen er inne i. NSStringFromSelector () konverterer den til en streng. Dette er en rask og enkel måte å få navnet på den nåværende metoden uten å måtte skrive det ut manuelt.

La oss kaste en navigasjonsregulator og en fanebryter inn i blandingen. Denne gangen bruker vi Storyboards.

Opprett en ny fil, og under iOS> brukergrensesnitt, velge storyboard. Sett enhetens familie til iPhone, og nev det NavStoryBoard.


Fra objekter bibliotek, dra og slipp a Navigasjonskontroller objekt inn i lerretet. Dra og slipp a bar knapp element inn i venstre side av navigasjonsfeltet i bordvisningskontrollenhet betegnet som "Root View Controller". Dette inneholder tabellvisningen i lerretet. Gi det noe navn. Jeg har kalt det"Venstre". Formålet er å bekrefte koden vi skrev for å få menylinjen til å skjule / avsløre knappen som sin venstre knapp på navigasjonslinjen, og skyve eventuelle allerede til stede knapper til høyre. Til slutt drar du en Vis kontrolleren eksempel og plasser den til høyre for kontrolleren med tittelen "Root View Controller"i lerretet.

Klikk hvor det står "Tabellvisning"i midten av den andre kontrolleren, og i attributter inspektør endre innholdet fra "Dynamisk Prototype" til "Statiske celler".

Endrer celleinnholdstype fra dynamisk til statisk

Dette vil føre til at tre statiske tabellvisningsceller vises i grensesnittbyggeren. Slett alt annet enn ett av disse tabellvisningscellene, og hold nede Styre, klikk og dra fra den gjenværende cellen til visningsregulatoren helt til høyre og slipp ut. Å velge "trykk"under Utvalgssegment. Alt dette gjør at en segue til høyre vises kontrolleren når du klikker på den ensomme cellen fra tabellvisningen. Hvis du vil, kan du slippe en UILabel på bordcellen for å gi den litt tekst. Din storyboard bør se ut som bildet nedenfor.

NavStoryBoard

Til slutt, la oss legge til en fanebladskontroller. Akkurat som du gjorde tidligere, opprett en storyboard filen og ring den TabStoryBoard. Dra og slipp a kontrollpanel på fanen element fra objektbibliotek inn i lerretet. Den kommer forhåndskonfigurert med to faner, og hvis du vil kan du endre bakgrunnsfargen til de to tabbevisningsregulatorene ved å klikke på visningen som svarer til enten å se kontrolleren og endre "bakgrunn"alternativet i Attributtsinspektør. På denne måten kan du bekrefte at visning av kontroller på kontrollpanelet gjennom fanen fungerer som den skal.

Din historiebrett skal se slik ut.

4. Konfigurere App Delegate

Nå er det på tide å sette alt opp i AppDelegate.

Erstatt koden i AppDelegate.m med følgende kode.

 #import "AppDelegate.h" #import "RootController.h" #import "ViewController.h" @implementation AppDelegate - (BOOL) søknad: (UIApplication *) søknad didFinishLaunchingWithOptions: (NSDictionary *) launchOptions self.window = [[UIWindow alloc] initWithFrame: grenser for [[UIScreen mainScreen]]]; UIStoryboard * tabStoryBoard = [UIStoryboard storyboardWithName: @ "TabStoryboard" bundle: null); UIStoryboard * navStoryBoard = [UIStoryboard storyboardWithName: @ "NavStoryboard" bunt: null); UINavigationController * navController = [navStoryBoard instantiateViewControllerWithIdentifier: @ "Nav Controller"]; UITabBarController * tabController = [tabStoryBoard instantiateViewControllerWithIdentifier: @ "Tab Controller"]; ViewController * redVC, * greenVC; redVC = [[ViewController alloc] init]; greenVC = [[ViewController alloc] init]; redVC.view.backgroundColor = [UIColor redColor]; greenVC.view.backgroundColor = [UIColor greenColor]; RootController * menuController = [[RootController allokere] initWithViewControllers: @ [tabController, redVC, greenVC, navController] ogMenuTitles: @ [@ "Tab", @ "Red", @ "Green", @ "Nav"]]; self.window.rootViewController = menuController; self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; returnere JA; 

Alt vi gjorde var å lage forekomster av ViewController og instantier navigasjons- og kategorien kontrolleren fra de to storyboards. Vi passerte dem i en matrise til vår RootControllers tilfelle. Det er containerkontrolleren vi implementerte i starten. Vi gjorde dette sammen med en rekke strenger for å nevne visningskontrollene i menyen. Nå skal vi bare angi vår initialiserte Root Controller-forekomst som vinduet rootViewController eiendom.

Bygg og kjør appen. Du har nettopp implementert containerinneslutning! Trykk på de forskjellige tabellcellene i menyen for å erstatte det synlige lysbildet med den nye som skyves inn fra høyre. Legg merke til hvordan, for navigasjonsstyringsinstansen (kalt "NavC"i menyen),"Venstre"-knappen har flyttet ett sted til høyre, og menylinjeknappen har tatt opp venstre stilling. Du kan endre retningen til landskapet og kontrollere at alt ser riktig ut.

Simulator skjermbilder

Konklusjon

I denne innledende veiledningen så vi på hvordan kontrollenhetskontrollen er implementert i iOS 6. Vi utviklet en enkel versjon av et tilpasset appgrensesnitt som har fått mye popularitet og ofte sett i svært brukte apper som Facebook og Path. Implementeringen vår var så enkel som mulig, så vi kunne dissekere det enkelt og få grunnleggende rett. Det er mange sofistikerte åpenkilde implementeringer av denne typen kontroller som du kan laste ned og studere. Et raskt Google-søk dukker opp JASidePAnels og SWRevealViewController, blant andre.

Her er noen ideer for deg å jobbe med.

  • Gjør implementeringen mer fleksibel og APIen mer tilpassbar.
  • Gjør grensesnittet vakrere. Du kan tilpasse tabellutsnittet celle utseende, eller la visningen kontrolleren synspunkt kaste en skygge på menyen for å låne grensesnittet litt dybde.
  • Gjør grensesnittet bedre til orienteringen. Husk at dine barnevise kontrollører mottar rotasjonsvarsler, så det er her du begynner!
  • Gjennomfør gestusgjenkjenning slik at du kan dra en visningsregulator til venstre og høyre over skjermen som et alternativ til å klikke på menyknappen.
  • Design og utvikle en helt ny og ny appstrøm og realiser brukergrensesnittet i kode. Sjansene er at du må bruke skjermkontrollens inneslutning!

En ting jeg vil nevne her er at i Xcode 4.5 og videre, er det et nytt grensesnittbyggerobjekt som heter "Containervisning"som kan vise innholdet i en visningskontroller, og dermed brukes til å implementere inneslutning direkte i din storyboard! Glad koding!