Genomförande av Container Containment - Skjutreglage

I den här handledningen genomför vi en minimalistisk version av Facebook / Path-style gränssnitt. Målsättningen är att förstå hur man använder kontrollenhetens kontroll för att implementera anpassat flöde i din app.


Teoretisk översikt

Visa kontroller är en viktig del av någon iOS-applikation, oavsett hur liten, stor, enkel eller komplex. De tillhandahåller "limlogiken" mellan datamodellen i din app och användargränssnittet.

I stort sett finns det två typer av visningsstyrare:

  • Innehållsregulatorer: Dessa ansvarar för att visa och hantera synligt innehåll.
  • Container controllers: Dessa hanterar innehållsinställningsregulatorer, och de ansvarar för appens övergripande struktur och flöde.

En containerkontrollant kan ha viss synlig komponent i sig, men fungerar i grunden som värd för innehållsinställningsregulatorer. Containercontrollers tjänar till att "trafikera" kommandon och förflyttningar av innehållsregulatorer.

UINavigationController, UITabBarController och UIPageViewController är exempel på kontroller för behållare som skickar med iOS SDK. Tänk på hur de tre är olika när det gäller de ansökningsflöden som de ger upphov till. Navigationsstyrenheten är utmärkt för en applikation med borrningstyp, där det val som användaren gör på en skärm påverkar vilka val han presenterar på nästa skärm. Kontrollpanelen för flikfältet är utmärkt för appar med oberoende funktioner, vilket gör det enkelt att byta genom att bara trycka på en flikknapp. Slutligen presenterar sidvisningsstyrenheten en bokmetafor, så att användaren kan vända fram och tillbaka mellan sidor av innehåll.

Den viktigaste saken att komma ihåg här är att en verklig skärm av innehåll som presenteras genom någon av dessa behållare måste kontrolleras själva, både vad gäller de data som den härleddes från (modellen) och presentationen på skärmen (vyn), vilket igen skulle vara jobbet hos en vykontrollant. Nu pratar vi om innehållsregulatorer. I vissa appar, särskilt på iPad, eftersom dess större skärm tillåter att mer innehåll visas samtidigt kan olika visningar på skärmen till och med behöva hanteras oberoende. Detta kräver samtidigt flera skärmbilder på skärmen. Allt detta innebär att visningsstyrarna i en väl utformad app ska implementeras på hierarkiskt sätt med både behållare och innehållsutsiktskontrollanter som spelar sina respektive roller.

Före iOS 5 fanns det inga sätt att deklarera ett hierarkiskt förhållande (mellan parent-child) mellan två visningsstyrare och därför inte någon "riktig" sätt att implementera ett anpassat applikationsflöde. Man antingen hade att göra med de inbyggda typerna, eller göra det på ett slumpmässigt sätt, vilket i grunden bestod av stickande visningar som hanterades av en bildskärmskontroller i visningshierarkin för vyn som hanteras av en annan bildskärmskontroller. Detta skulle skapa inkonsekvenser. En vy skulle till exempel hamna i synkroniseringshierarkin för två kontrollanter utan att någon av dessa kontroller erkänner den andra, vilket ibland leder till konstigt beteende. Inhängning infördes i IOS 5 och raffinerades något i IOS 6, och det gör det möjligt att formalisera begreppet föräldra- och barnvisningskontroller i en hierarki. I huvudsak kräver korrekt inställning av kontrollkontrollen att om visning B är en undervy (barn) för visning A och om de inte är under hantering av samma bildkontrollen, måste B: s visningsstyrenhet göras A: s visningsstyrnings barn.

Du kanske frågar om det finns någon konkret fördel som erbjuds genom att se kontrollenhetens innehav utöver fördelen med den hierarkiska konstruktionen vi diskuterade. Svaret är ja. Tänk på att när en bildkontroll kommer på skärmen eller går bort, kan vi behöva konfigurera eller riva ner resurser, städa upp, hämta eller spara information från / till filsystemet. Vi vet alla om utseende callbacks. Genom att uttryckligen förklara förhållandet mellan föräldra och barn försäkrar vi att förälderkontrollanten vidarebefordrar callbacks till sina barn när någon kommer på eller går av skärmen. Rotationsanrop måste vidarebefordras. När orienteringen ändras måste alla visningsstyrare på skärmen veta så att de kan anpassa sitt innehåll på lämpligt sätt.

Vad innebär allt detta i form av kod? Visa kontroller har en NSArray egendom som heter childViewControllers och vårt ansvar innefattar att lägga till och ta bort barnsynkontroller till och från denna grupp i föräldern genom att ringa till lämpliga metoder. Dessa metoder inkluderar addChildViewController (kallas föräldern) och removeFromParentViewController (kallas barnet) när vi försöker göra eller bryta föräldra-barnsrelationen. Det finns också ett par meddelandemeddelanden som skickas till barnvynskontrollen vid början och slutet av tilläggs- / borttagningsprocessen. Dessa är willMoveToParentViewController: och didMoveToParentViewController:, skickas med lämplig moderkontroll som argument. Argumentet är noll, om barnet tas bort. Som vi ser kommer ett av dessa meddelanden att skickas automatiskt till oss medan den andra kommer att vara vårt ansvar att skicka. Det beror på om vi lägger till eller tar bort barnet. Vi ska studera den exakta sekvensen kort när vi implementerar saker i kod. Barnkontrollanten kan svara på dessa anmälningar genom att tillämpa motsvarande metoder om det behövs något för att förbereda dessa händelser.

Vi måste också lägga till / ta bort de synpunkter som är associerade med barnvynskontrollen till föräldrars hierarki, med hjälp av metoder som addSubview: eller removeFromSuperview), inklusive att utföra några medföljande animeringar. Det finns en bekväm metod (-) transitionFromViewController: toViewController: Längd: alternativ: animationer: utförande: som gör det möjligt för oss att effektivisera processen för att byta barnvisningskameror på skärmen med animeringar. Vi tittar på exakta detaljer när vi skriver koden - vilken är nästa!


1. Skapa ett nytt projekt

Skapa en ny iOS-app i Xcode baserat på "Tom applikation"mall. Gör det till en iOS-app med ARC-aktiverad. Ring den VCContainmentTut.

Skapa ett nytt projekt

2. Implementering av Container View Controller

Skapa en ny klass som heter RootController. Gör det till en UIViewController underklass. Kontrollera att alla kryssrutor är avmarkerade. Detta kommer att bli vår undervågen för behållarevisningskontroll.


Ersätt koden i RootViewController.h med följande.

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

Vår containerkontrollant har en tabellvy som fungerar som vår meny och genom att knacka på vilken cell som helst ersätts den nuvarande synliga kontrollenheten av den som valts genom användarens kran.

Med hänvisning till punkterna i koden,

  1. Vår rotatorkontrollern dubblerar som menyns (dvs. tabellvyens) delegat och datakälla.
  2. Vi erbjuder ett extremt enkelt API (vad gäller vår containerklassanvändare) som består av en initialiserare som tar upp en lista över visningsstyrare som vår root-controller ska innehålla och en lista över strängar som representerar titlarna för varje bildskärmskontroller i meny. Det här är så att vi kan koncentrera oss på grunderna. När du förstår dessa kan du göra API så anpassningsbart som du vill.

Låt oss ta en titt framåt för att se vad vår färdiga produkt kommer att se ut så att du har en mental bild för att associera implementeringen med.


Det kommer att bidra till att inse att vår kontrollenhet för behållare är ganska lik en flikvynskontroller. Varje objekt i menyn motsvarar en oberoende bildkontroll. Skillnaden mellan vår "glidande meny"Controller och flikkontrollen är visuellt för det mesta. Uttrycket"glidande meny"är lite av en missnöverskott eftersom det faktiskt är innehållsvisningskontrollen som glider för att dölja eller avslöja menyn nedan.

Fortsätt till implementeringen, ersätt all kod i RootController.m med följande kod.

 #define kExposedWidth 200.0 #define kMenuCellID @ "MenuCell" #import "RootController.h" @interface RootController () @property (nonatomic, strong) UITableView * -menyn; @property (nonatomic, strong) NSArray * viewControllers; @property (nonatomic, strong) NSArray * menyTitlar; @property (nonatomic, assign) NSInteger indexOfVisibleController; @property (nonatomic, assign) BOOL ärMenuVisible; @end @implementation RootController - (id) initWithViewControllers: (NSArray *) viewControllers andMenuTitles: (NSArray *) menyTitlar if (self = [super init]) NSAssert (self.viewControllers.count == self.menuTitles.count, @ "Det måste finnas en och enda menotitel som motsvarar varje vykontroll!"); // (1) NSMutableArray * tempVCs = [NSMutableArray arrayWithCapacity: viewControllers.count]; self.menuTitles = [menuTitles copy]; för (UIViewController * vc i viewControllers) // (2) if (! [vc isMemberOfClass: [UINavigationController class]]) [tempVCs addObject: [[UINavigationController allokerar] initWithRootViewController: vc]];  annat [tempVCs addObject: vc]; UIBarButtonItem * revealMenuBarButtonItem = [[UIBarButtonItem alloc] initWithTitle: @ "Meny" stil: UIBarButtonItemStylePlain mål: självåtgärd: @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;  återvänd själv  - (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; [självjusteringsinnehållFrameAccordingToMenuVisibility]; // (7) [self.viewControllers [0] didMoveToParentViewController: self]; // (8) - (void) toggleMenuVisibility: (id) avsändare // (9) self.isMenuVisible =! Self.isMenuVisible; [självjusteringsinnehållFrameAccordingToMenuVisibility];  - (void) adjustContentFrameAccordingToMenuVisibility // (10) UIViewController * visibleViewController = self.viewControllers [self.indexOfVisibleController]; CGSize size = visibleViewController.view.frame.size; om (self.isMenuVisible) [UIView animateWithDuration: 0.5 animeringar: ^ visibleViewController.view.frame = CGRectMake (kExposedWidth, 0, size.width, size.height); ];  else [UIView animateWithDuration: 0.5 animeringar: ^ visibleViewController.view.frame = CGRectMake (0, 0, size.width, size.height); ];  - (void) replaceVisibleViewControllerWithViewControllerAtIndex: (NSInteger) index // (11) om (index == self.indexOfVisibleController) returnera; UIViewController * incomingViewController = self.viewControllers [index]; incomingViewController.view.frame = [self offScreenFrame]; UIViewController * outgoingViewController = self.viewControllers [self.indexOfVisibleController]; CGRect visibleFrame = self.view.bounds; [outgoingViewController willMoveToParentViewController: nil]; // (12) [self addChildViewController: incomingViewController]; // (13) [[UIApplication sharedApplication] startIgnoringInteractionEvents]; // (14) [self transitionFromViewController: outgoingViewController // (15) toViewController: incomingViewController duration: 0.5 options: 0 animations: ^ outgoingViewController.view.frame = [self offScreenFrame];  fullbordad: ^ (BOOL slutförd) [UIView animateWithDuration: 0.5 animeringar: ^ outgoingViewController.view removeFromSuperview]; [self.view addSubview: incomingViewController.view]; inkommandeViewController.view.frame = visibleFrame; [[UIApplication sharedApplication] endIgnoringInteractionEvents]; // (16)]; [incomingViewController didMoveToParentViewController: self]; // (17) [outgoingViewController removeFromParentViewController]; // (18) self.isMenuVisible = NEJ; self.indexOfVisibleController = index; ];  // (19): - (NSInteger) numberOfSectionsInTableView: (UITableView *) tableView return 1;  - (NSInteger) tableView: (UITableView *) tableView numberOfRowsInSection: (NSInteger) avsnitt return self.menuTitles.count;  - (UITableViewCell *) tableView: (UITableView *) tableVisa cellForRowAtIndexPath: (NSIndexPath *) indexPath UITableViewCell * cell = [tableView dequeueReusableCellWithIdentifier: kMenuCellID]; cell.textLabel.text = self.menuTitles [indexPath.row]; returcell;  - (void) tableView: (UITableView *) tableView didSelectRowAtIndexPath: (NSIndexPath *) indexPath [self replaceVisibleViewControllerWithViewControllerAtIndex: indexPath.row];  - (CGRect) offScreenFrame returnera CGRectMake (self.view.bounds.size.width, 0, self.view.bounds.size.width, self.view.bounds.size.height);  @slutet

Nu för en förklaring av koden. De delar som jag har markerat för tonvikt är särskilt relevanta för inneslutningsimplementeringen.

  1. Först gör initieraren en enkel kontroll för att se till att varje bildkontroll har fått en meny titel. Vi har inte gjort någon typkontroll för att säkerställa att var och en av de två raderna som passerat till initialiseraren innehåller rätt typ av objekt, UIViewController och NSString typerna respektive. Du kan överväga att göra det. Observera att vi upprätthåller arrays för var och en av dessa, kallade viewControllers, och menuTitles.
  2. Vi vill att det ska finnas en knapp som, när den är tagen, visar eller gömmer menyn. Min enkla lösning på var knappen skulle vara var att sätta varje visningsstyrenhet vi mottog från initialiseraren inne i en navigeringskontroll. Detta ger oss en ledig navigeringsfält som en knapp kan läggas till, såvida inte den kontrollerade styrenheten redan var en navigeringsenhet, i vilket fall vi inte gör något extra.
  3. Vi skapar ett streckknappsobjekt som utlöser menyens utseende eller gömmer genom att skjuta den visningsregulator som är synlig. Vi lägger till den i navigeringsfältet genom att flytta några befintliga knappar på navigeringsfältet till höger. Vi gör det här eftersom den visade kontrollenheten redan är en navigationsstyrenhet med befintliga streckknappar.
  4. Vi instanserar vår meny som en tabellvy och tilldelar root-kontrollen själv som delegat och datakälla.
  5. I viewDidLoad, Efter att du har konfigurerat och lägger till menybordet i vår rotatorns vy, inser vi in ​​i vår app den första visningsregulatorn i viewControllers array. Genom att skicka addChildViewController: meddelande till vår root controller, utför vi vårt första inneslutningsrelaterade ansvar. Du borde veta att detta orsakar meddelandet willMoveToParentViewController: att bli uppmanad på barnkontrollanten.
  6. Observera att vi explicit måste lägga till vår barnkontrollans syn på föräldrars synhierarki!
  7. Vi ställer in menyn för att vara synlig i början och anropa en metod som justerar visningen av synlig innehållsregulatorens ram, med hänsyn till menyns synlighet. Vi kommer att undersöka denna metods detaljer inom kort.
  8. När barnvynsregulatorens syn sitter bekvämt i föräldrars synhierarki, vi skickar meddelandet didMoveToParentViewController till den extra barnkontrollen, med själv, RootController-förekomsten, som argumentet. I vårt barnkontroller kan vi genomföra den här metoden om vi behöver.
  9. En enkel metod som är kopplad till vår menyradsknapps åtgärd som växlar menyens synlighet genom att justera överläggningsvynsregulatorens vy på lämpligt sätt.
  10. Som namnet indikerar, adjustContentFrameAccordingToMenuVisibility Låt oss justera innehållsregulatorens ram för att berätta om menyn är dold eller inte. Om ja, överlappar det övervakningen. Annars flyttas den till höger genom kExposedWidth. Jag har satt det till 200 poäng.
  11. Återigen, så tydligt angivet med namnet, replaceVisibleViewControllerWithViewControllerAtIndex tillåter oss att byta ut kontrollerare och motsvarande synpunkter från hierarkin. För att dra av vår animering, som består av att skjuta den utbytta kontrollenheten avskärmen till höger och sedan ta in ersättningsregulatorn från samma plats definierar vi några rektangulära ramar.
  12. willMoveToParentViewController med noll. När vi har slutfört det här steget, upphör den här kontrollenheten att ta emot utseende och rotationsanrop från föräldern. Det här är meningsfullt eftersom det inte längre är en aktiv del av appen.
  13. Vi lägger till kommandot för inkommande visning som ett barn till rotkontroller, som vi gjorde i början.
  14. Vi börjar ignorera användarinteraktionshändelser för att låta vår kontroller byta över det smidigt.
  15. Denna bekvämlighetsmetod tillåter oss att animera avlägsnandet av den utgående styrenheten och ankomst av den inkommande en samtidigt som den nödvändiga sekvensen av händelser som involveras i tillsats- och borttagningsprocessen för barnvy kontrolleras. Vi animerar den utgående VC: ns vy för att skjuta offscreen till höger, och efter att animeringen är klar tar vi bort den från visningshierarkin. Vi animerar sedan den inkommande vynkontrollen för att skjuta in från samma plats avskärmen och uppta den plats som tidigare tagits upp av den utgående regulatorns vy.
  16. Vi gör det möjligt för vår app att acceptera inkommande interaktionshändelser, eftersom vår kontroll av byteskontrollen har slutförts.
  17. Vi meddelar inkommande visningskontrollen att den har flyttats till containerkontrollern genom att skicka den till didMoveToParentViewController meddelande med själv som argumentet.
  18. Vi tar bort den utgående styrenheten från behållaren genom att skicka den till removeFromParentViewController meddelande. Du borde veta det didMoveToParentViewController: med noll som ett argument skickas till dig.
  19. Vi implementerar menyns tabellvyns delegat och datakällans protokollmetoder, som är ganska enkla. Detta innefattar att utlösningssteget (11) för visningskontrollen utlöses när ett nytt objekts cell tappas i menyn via -Tableview: didSelectRowAtIndexPath: metod.

Du kan ha hittat sekvensen av samtal som hör samman med kontrollenhetens inbyggnad lite förvirrande. Det hjälper till att sammanfatta.

    När du lägger till en barnvisningskontroll till en förälder:
  • Ring upp addChildViewController: på föräldern med barnet som argumentet. Detta orsakar meddelandet willMoveToParentViewController: att skickas till barnet med föräldern som argumentet.
  • Lägg barnets syn som en undervy av föräldrars syn.
  • Ring exakt didMoveToParentViewController: på barnet med föräldern som argumentet.
    När du tar bort en barnvisningskontroll från dess förälder:
  • Ring upp willMoveToParentViewController: på barnet med noll som argumentet.
  • Ta bort barnets syn från övervakningen.
  • Skicka removeFromParentViewController till barnet. Orsakerna orsakar meddelandet didMoveToParentViewController med noll som argumentet att skickas till barnet på dina vägnar.

3. Testning

Låt oss testa de olika typerna av kontrollerare som läggs till i vår root controller! Skapa en ny underklass av UIViewController kallad ViewController, håller valfria valfria alternativ.

Byt koden i ViewController.m med följande kod.

 #import "ViewController.h" @interface ViewController () @end @implementation ViewController - (void) willMoveToParentViewController: (UIViewController *) förälder NSLog (@ "% @ (% p) -% @", NSStringFromClass ([självklass] ), själv, NSStringFromSelector (_cmd));  - (void) didMoveToParentViewController: (UIViewController *) förälder NSLog (@ "% @ (% p) -% @", NSStringFromClass ([självklass)), själv, NSStringFromSelector (_cmd));  - (void) viewWillAppear: (BOOL) animerad [super viewWillAppear: animated]; NSLog (@ "% @ (% p) -% @", NSStringFromClass ([självklass)), själv, NSStringFromSelector (_cmd));  - (void) viewDidAppear: (BOOL) animerad [super viewDidAppear: animated]; NSLog (@ "% @ (% p) -% @", NSStringFromClass ([självklass)), själv, NSStringFromSelector (_cmd));  - (tom) willRotateToInterfaceOrientation: (UIInterfaceOrientation) toInterfaceOrientation duration: (NSTimeInterval) duration [super willRotateToInterfaceOrientation: toInterfaceOrientation duration: duration]; NSLog (@ "% @ (% p) -% @", NSStringFromClass ([självklass)), själv, NSStringFromSelector (_cmd));  - (void) didRotateFromInterfaceOrientation: (UIInterfaceOrientation) fromInterfaceOrientation [super didRotateFromInterfaceOrientation: fromInterfaceOrientation]; NSLog (@ "% @ (% p) -% @", NSStringFromClass ([självklass)), själv, NSStringFromSelector (_cmd));  @slutet

Det är inget speciellt med vår kontrollorgan själv, förutom att vi har överrullat de olika återuppringningarna så att vi kan logga in när våra ViewController Exempel blir ett barn till vår rotkontroller och ett utseende eller rotationshändelse inträffar.

I all tidigare kod, _cmd refererar till väljaren som motsvarar den metod som vår utförande är inuti. NSStringFromSelector () omvandlar den till en sträng. Det här är ett snabbt och enkelt sätt att få namnet på den nuvarande metoden utan att manuellt skriva ut det.

Låt oss kasta en navigeringskontroll och en flikkontroll i mixen. Den här gången använder vi Storyboards.

Skapa en ny fil, och under iOS> Användargränssnitt, välja storyboard. Ställ in enhetsfamiljen till iPhone, och namnge det NavStoryBoard.


Från objekt bibliotek, dra och släpp a Navigation Controller föremål in i duken. Dra och släpp a bar knapp punkt till vänster på navigeringsfältet i tabellvisningskontrollenhet betecknad som "Root View Controller".Detta innehåller tabellvyn i duken. Ge det något namn. Jag har namngett det"Vänster". Dess syfte är att verifiera koden som vi skrev för att få menyfältets hide / reveal-knapp att ta plats som den vänstra knappen på navigeringsfältet, trycka på redan befintliga knappar till höger. Dra slutligen en Visa kontrollenhet instans och placera den till höger om den registeransvarige med titeln "Root View Controller"i duken.

Klicka där det står "Tabellvy"i mitten av den andra kontrollenheten, och i attribut inspektör ändra innehållet från "Dynamisk prototyp"till"Statiska celler".

Ändra cellinnehållstyp från dynamisk till statisk

Detta kommer att få tre statiska tabellvynceller att visas i gränssnittsbyggaren. Radera alla utom en av dessa tabellvynceller och samtidigt hålla ned Kontrollera, klicka och dra från den återstående cellen till vykontrollen längst till höger och släpp ut. Välj "tryck" under Urvalssegment. Allt detta gör att en segue till höger bildskärmskontroller när du trycker på den lilla cellen från tabellvyn. Om du vill kan du släppa en UILabel på bordcellen för att ge den lite text. Din storyboard ska likna bilden nedan.

NavStoryBoard

Till sist, låt oss lägga till en flikfelsregulator. Precis som du gjorde tidigare, skapa en storyboard fil och ring det TabStoryBoard. Dra och släpp a fliken kontroller objekt från objekt bibliotek in i duken. Den kommer förkonfigurerad med två flikar och om du vill kan du ändra bakgrundsfärgen för de två flikvynskontrollerna genom att klicka på vyn som motsvarar antingen visningskontrollen och ändra "bakgrund"alternativet i Attribut Inspector. På så sätt kan du verifiera att kontrollen av visningskontrollen via fliken fungerar korrekt.

Din storyboard ska se ut så här.

4. Konfigurera App Delegate

Nu är det dags att sätta upp allt i AppDelegate.

Byt kod i AppDelegate.m med följande kod.

 #import "AppDelegate.h" #import "RootController.h" #import "ViewController.h" @implementation AppDelegate - (BOOL) ansökan: (UIApplication *) ansökan didFinishLaunchingWithOptions: (NSDictionary *) launchOptions self.window = [[UIWindow alloc] initWithFrame: gränser för [[UIScreen mainScreen]]; UIStoryboard * tabStoryBoard = [UIStoryboard storyboardWithName: @ "TabStoryboard" bunt: noll]; UIStoryboard * navStoryBoard = [UIStoryboard storyboardWithName: @ "NavStoryboard" bunt: noll]; 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 tilldela] initWithViewControllers: @ [tabController, redVC, greenVC, navController] ochMenuTitles: @ [@ "Tab", @ "Red", @ "Green", @ "Nav"]]; self.window.rootViewController = menuController; self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; returnera JA; 

Allt vi gjorde var att skapa instanser av ViewController och installa navigations- och flikkontrollen från de två storyboardsna. Vi passerade dem i en matris till vår RootControllers förekomst. Det är containerbehållaren som vi implementerade i början. Vi gjorde det här tillsammans med en rad strängar för att namnge vykontrollerna i menyn. Nu ska vi bara ange vår initialiserade Root Controller-instans som fönstret rootViewController fast egendom.

Bygg och kör appen. Du har just genomfört behållarens containment! Tryck på de olika tabellcellerna i menyn för att ersätta den synliga bilden med den nya som skjuter in från höger. Lägg märke till hur, för navigeringskontrollinstansen (namnet "NavC"i menyn),"Vänster"-knappen har flyttats en plats till höger och menyknappen har tagit upp vänster position. Du kan ändra orienteringen till landskapet och verifiera att allt ser ordentligt ut.

Simulator skärmbilder

Slutsats

I denna inledande handledning såg vi på hur kontrollen av kontrollenhet implementeras i IOS 6. Vi utvecklade en enkel version av ett anpassat appgränssnitt som har fått stor popularitet och ses ofta i mycket använda appar som Facebook och sökväg. Vårt genomförande var så enkelt som möjligt, så vi kunde enkelt dissekera det och få grundläggande grunder rätt. Det finns många sofistikerade open source-implementeringar av denna typ av controller som du kan ladda ner och studera. En snabb Google-sökning dyker upp JASidePAnels och SWRevealViewController, bland andra.

Här är några idéer för dig att arbeta på.

  • Gör implementeringen mer flexibel och API mer anpassningsbar.
  • Gör gränssnittet snyggare. Du kan anpassa tabellutsiktets cellutseende, eller låt din bildskärmskontrollers syn välj en skugga på menyn för att låna gränssnittet lite djup.
  • Gör gränssnittet bättre anpassat till orienteringen. Kom ihåg att dina barns kontroller kommer att få rotationsmeddelanden, så det är där du börjar!
  • Genomför gesterigenkänning så att du kan dra en vykontrollern till vänster och höger över skärmen som ett alternativ till att klicka på menyknappen.
  • Design och utveckla ett helt nytt och nytt appflöde och förverkliga användargränssnittet i kod. Chansen är att du måste använda sig av kontrollenhetens kontroll!

En sak som jag skulle vilja nämna här är att i Xcode 4.5 och framåt finns det ett nytt gränssnittsbyggareobjekt som heter "Behållarvy"som kan visa innehållet i en visningsregulator och sålunda användas för att genomföra inneslutning direkt i din storyboard! Glad kodning!