iphone programozás alapjai II. előadás A mai előadás témái I. Interface builder Az UI betöltés folyamata Outletek és Actionok II. További UI elemek Tableview Navigation és Tabbar Controllerek III. Gyakorlati példa I. Interface Builder
UI Építés módszerei I. Kézzel építjük fel kódból Minden lehetőséget ki tudunk használni Rengeteg ás átláthatatlan kód II. Kódgenerálás Látjuk mit csinál, ha akarjuk átírhatjuk Ha átírjuk, bukjuk az átszerkesztést, felesleges kódrészletek. III. Perzisztencia alapú Objektumokat paraméterezünk, majd írunk ki Ezt töltjük be programkódból MVC architektúra Hasonlóan épül fel, mint az egyéb MVC alapú nyelvekben Model: Belső adattárolási és feldolgozási objektumok. Egyszerűbb programoknál elhagyható View: Sokszor nem jelenik meg osztályokban, csak IB-vel összerakott View-ekban. Controller: A kód központi eleme elvégzi a view betöltést és kezeli a hozzá kapcsolódó alkalmazás logikát. Az UI betöltés folyamata Interface Builder XIB fájl UI a képernyőn Build Programkód Megjelenítés NIB fájl Betöltés Objektum példány
Az UI megtervezése Az IB képernyői Library Document Inspector A File s Owner a betöltő Controller objektum User Interface elemek Igen jól használható alapkészlet Alap beviteli és megjelenítő elemek Textfield, Button, Switch, Slider, Label, TextArea Speciális adatmegjelenítők Map, Image, Web, Table, DatePicker, Picker Navigációs elemek TabBarController Egyéb UI osztályok
Betöltés A betöltést a kontroller osztályok végzik (bizonyos esetekben maguk az UI osztályok is elvégezhetik, pl. TabBarController) CalculatorViewController* calculatorviewcontroller= [[CalculatorViewController alloc] initwithnibname:@"calculatorviewcontroller" bundle:nil]; A betöltött elemel megjelenítése sokféleképpen történhet (navigation controllerek, presentmodalviewcontroller), egyik legegyszerűbb: [window addsubview:viewcontroller.view]; [window makekeyandvisible]; A kóddal való összekötés Meg tudjuk tervezni, be tudjuk tölteni, meg tudjuk jeleníteni, de ez még kevés: Hogyan tudunk a kódból változtatni az UI-n? Hogyan tudjuk a UI események hatására műveleteket végezni? Lényegében az alábbi két dolgot kell megoldanunk: Referenciát (mutatót) kell szereznünk a betöltött UI struktúra bizonyos objektumaira Meg kell adnunk eseménykezelőket bizonyos UI objektumok egyes eseményeire Outletek Olyan változókat (Outleteket) adhatunk meg, amelyekbe a rendszer betöltéskor automatikusan beteszi a megadott objektumokat. Belehelyezzük a kódba az Outlet propertyket IBOutlet jelölőt kell használnunk, innen tudja az Interface Builder, hogy az adott property egy Outlet @interface CalculatorViewController : UIViewController {! UITextField* resultfield; @property (nonatomic,retain) IBOutlet UITextField* resultfield; Az Interface Builderben beállítjuk, hogy melyik objektumot akarjuk betölteni a property-be. A View betöltéskor a rendszer automatikusan behelyezi a hivatkozást. A kódban típusosan elérjük a betöltött UI elemet.
Actionok Megadhatjuk azokat a metódusokat, amelyeket a rendszer meghívjon bizonyos események bekövetkeztekor Belehelyezzük a kódba az Action metódusokat Az IBAction visszatérési értéket kell használni, ami igazából void, de innen tudja a rendszer, hogy ez egy Action metódus. Paramétere vagy nincs a metódusnak, vagy egy (id) sender paramért kaphat, ami azt az objektumot tartalmazza, amelyre vonatkozik az esemény. -(IBAction) someevent:(id)sender; Az Interface Builderben beállítjuk, hogy melyik objektum melyik eseménye váltsa ki a hívást. (pl. Touch Down) Az esemény bekövetkeztekor automatikusan meghívódik a metódus. Retina Display A iphone4 megjelenésével megszűnt a kijelző egységessége: A felbontás mindkét irányban megduplázódott A képarány változatlan maradt A régi programok futtathatósága pixel duplázással adott, de egy egyszerű módszert kerestek az új programok felkészítésére A következőkre kell figyelnünk: Az Interface Builderben megadott koordináták duplázódnak A UI-t általában képekből rakjuk össze, iphone 4-en lehet minden képből egy image@2x.png fájlt készíteni, így nagyobb felbontással dolgozhatunk. Speciális elemeknél (pl. CoreGraphics külön módosítás kell) II. További UI elemek
Táblázatok Egyik leggyakrabban használt képernyő elem Például hírlisták Kontaktok Levelek Lista jellegű tartalmakhoz, bármilyen felépítésben Mindig egy oszlop van De a sorok felépítése nem kötött Függőlegesen mozgatható Táblázatok felépítése Alapvetően két szintű Csoportok Sorok Két fő típusa van a felépítésnek Plain esetben kiemelt csíkok választják el a csoportokat Groupped esetben grafikailag jobban összehúzott A cellák felépítése paraméterezhető, de szükség esetén teljesen egyediesíthető Automatikus a scrollozódás, paraméterezhető átsorrendezés DataSource és Delegate Inicializáláskor az UITableView vár két objektumot, amelyeket Outletként lehet bekötni UITableViewDatasource: Azt adja meg, hogy milyen és mennyi csoportot, sort akarunk megjeleníteni milyen tartalommal. UITableViewDelegate: DataSource Adatok lekérése TableView Delegate Események A tábla eseményeivel hívja a rendszer ezt az osztályt, például sor kiválasztása
Datasource metódusok - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableview Kirajzolásnál ez hívódik először, hogy megtudja, hány csoport van - (NSInteger)tableView:(UITableView *)tableview numberofrowsinsection:(nsinteger)section Minden látszó csoportra meghívódik, visszaadva a sorok számát - (UITableViewCell *)tableview:(uitableview *)tableview cellforrowatindexpath:(nsindexpath *)indexpath Visszaadja egy adott csoport adott sorához tartozó megjelenített elemet CellForRowAtIndexPath - (UITableViewCell *)tableview:(uitableview *)tableview cellforrowatindexpath:(nsindexpath *)indexpath { static NSString *CellIdentifier = @"Cell"; UITableViewCell *cell = [tableview dequeuereusablecellwithidentifier:cellidentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initwithstyle:uitableviewcellstyledefault reuseidentifier:cellidentifier] autorelease]; // Configure the cell... return cell; Egy View-t ad vissza, amely megjeleníti az adott cellát Először megpróbál egy korábbi cellát újrahasználni (lehet, hogy a tábla 100 soros, de egyszerre mindig csak 10 látszik Ha nincs újra felhasználható, akkor készít egy újat Végül beállítjuk a cella paramétereit Delegate metódusok Szabályozhatjuk a tábla celláinak méretét Szabályozhatjuk a headereket és footereket Átrendezési események kezelése De a leggyakoribb használat a sor kiválasztása: - (void)tableview:(uitableview *)tableview didselectrowatindexpath: (NSIndexPath *)indexpath A rendszer átadja a kiválasztott sort rákattintáskor
NavigationController NavigationController Több, hierarchikus képernyő közötti navigációt segíti Stack (verem) jellegű működéssel rendelkezik Úgy tudunk lépkedni az egyes képernyők között, hogy a visszalépéseknél nem kel tudnunk mi volt a szülő képernyőnk Nagyon gyakran használják táblázatokkal együtt NavigationBar Képernyő tetején elhelyezkedő sáv Megmutatja az adott view címét Lehetőséget ad a visszalépésre az előző szintre A vissza gombon mindig az előző szint címe van Jobb oldalán van hely egy szabad gombnak
Metódusok - (id)initwithrootviewcontroller:(uiviewcontroller *) rootviewcontroller Létrehozzuk az első viewcontroller megadásával - (void)pushviewcontroller:(uiviewcontroller *)viewcontroller animated:(bool)animated Az eddigieket lejjebb nyomjuk a verembe és aktívnak hozzáadjuk a megadott view controllert - (UIViewController *)popviewcontrolleranimated:(bool)animated A legutolsó view-et eldobjuk és kivesszük a verem legtetején lévőt TabBarController Több view között lehet fülekkel váltogatni Képernyő alján szokott elhelyezkedni Általában ez a legkülső navigációs elem Maximum 5 lap fér el, ezután megjelenik a more lehetőség TabBarController Lehet benne NavigationController, de mindig a TabBarController a külső elem Általában nem igényel programozás, beállítjuk a betöltendő ViewControllereket, és a többit kezeli magától Egyszerre mindig egy fül lehet aktív, a többi megőrzi állapotát és bármikor átválthatunk
III. Gyakorlati példa Egyszerű számológép Négy alapművelet Teljes egészében felépítjük a programot 1. Projekt létrehozás 2. UI tervezés 3. Kódváz elkészítése 4. Összekötés 5. Kód kidolgozása Projekt létrehozása
XIB megnyitása XIB szerkesztése Összeállítjuk a felületet Drag&Drop húzogassuk be az egyes elemeket Segédvonalakkal pozícionáljunk Interfész elemek TextField a kijelző Jobbra igazítás, Enabled kiszedése Round Rect Button a számoknak Állítsuk be a tag értékét a szám értékére Round Rect Button a műveleteknek
A kód alapelemei Generált Osztályok: CalculatorAppDelegate: az indítóosztály, alkalmazás életciklussal kapcsolatos feladatok CalculatorViewController: Az elkészítendő view-hez tartozó programlogika Mi a CalculatorViewController-ben dolgozunk, ez az osztály felel a view-val kapcsolatos minden tevékenységért Elsőként a.h fájlban dolgozunk CalculatorViewController.h #import <UIKit/UIKit.h> @interface CalculatorViewController : UIViewController {! UITextField* resultfield; @property (nonatomic,retain) IBOutlet UITextField* resultfield; -(IBAction) pushednumber:(id)sender; -(IBAction) pushedplus; -(IBAction) pushedminus; -(IBAction) pushedmul; -(IBAction) pusheddiv; -(IBAction) pushedequal; @end resultfield IBOutlet: azért, hogy kódból elérjük az eredményjelzőt. pushednumber: Esemény üzenet, ha valamelyik számgombot nyomta meg. pushedplus, pushedminus, pushedmul, pusheddiv, pushedequal: Esemény kezelők a műveletekhez Outlet Bekötés Outlet bekötés: Kiválasztjuk a File s Owner elemet (Document Window) és jobb gombot nyomunk rajta Kiválasztjuk azt az elemet amit be akarunk kötni (itt resultfield) A kis karikára nyomva folyamatosan húzva kiválasztjuk a bekötendő elemet
Action Bekötés Action bekötés: Kiválasztjuk az adott elemet, amelyet be kívánunk kötni és jobb gombot nyomunk rajta Kiválasztjuk az adott eventet, amit bekötünk (itt Touch Up Inside) A kis karikára nyomva folyamatosan húzva kiválasztjuk a File s Owner-t Megjelennek a felvett IBAction metódusok, amelyek közül kiválasztjuk, amit szeretnénk Action bekötés Kidolgozzuk a kódot Megvalósítjuk a számológép működést Ehhez először a CalculatorViewController.h-ban vesszük fel az új elemeket Szükség van két belső (long) tárolóra, valamint egy enumra, ami mutatja mi az aktuális művelet Szükség van egy belső számolási metódusra (calculate)
Kidolgozzuk a kódot CalculatorViewController.h #import <UIKit/UIKit.h> @interface CalculatorViewController : UIViewController {! UITextField* resultfield;! long number,resultnumber;! enum Operation {none,plus,minus,mul,divide,equal operation; @property (nonatomic,retain) IBOutlet UITextField* resultfield; -(void) calculate; -(IBAction) pushednumber:(id)sender; -(IBAction) pushedplus; -(IBAction) pushedminus; -(IBAction) pushedmul; -(IBAction) pusheddiv; -(IBAction) pushedequal; @end CalculatorViewController.m @Synthesize-oljuk a resultfield-et. #import "CalculatorViewController.h" @implementation CalculatorViewController @synthesize resultfield; Inicializáljuk a belső változóinkat betöltéskor - (void)viewdidload { [super viewdidload];! number=0;! resultnumber=0;! operation=none; Felszabadítjuk a változóinkat. - (void)dealloc {! [resultfield release]; [super dealloc]; CalculatorViewController.m -(void) calculate{! switch (operation) {!! case plus:!!! resultnumber+=number;!!! number=0;!!! break;!! case minus:!!! resultnumber-=number;!!! number=0;!!! break;!! case mul:!!! resultnumber=resultnumber*number;!!! number=0;!!! break;!! case divide:!!! resultnumber=resultnumber/number;!!! number=0;!!! break; Az aktuális művelet függvényében elvégezzük a számítást!! case equal:!!! break;!!!!! default:!!! resultnumber=number;!!! number=0;!!! break;!! Az eredményt betesszük az eredmény számolóba Az aktuális számot kitöröljük Az aktuális művelet függvényében elvégezzük a számítást Az eredményt betesszük az eredmény számolóba Az aktuális számot kitöröljük
CalculatorViewController.m -(IBAction) pushednumber:(id)sender{! if (operation==equal) {!! operation=none;!! number=0;!! UIButton* button=(uibutton*)sender;! number=number*10+button.tag;! resultfield.text=[nsstring stringwithformat:@"%d",number]; -(IBAction) pushedplus{! [self calculate];! operation=plus; -(IBAction) pushedminus{! [self calculate];! operation=minus; -(IBAction) pushedmul{! [self calculate];! operation=mul; -(IBAction) pusheddiv{! [self calculate];! operation=divide; -(IBAction) pushedequal{! [self calculate];! operation=equal;! resultfield.text=[nsstring stringwithformat:@"%d",resultnumber] ;! Megvalósítjuk az esemény kezelőket Mindenhol végrehajtjuk az aktuális műveletet, majd rögzítjük az újat Elkészültünk, próbáljuk ki! Gyakorló feladat Egészítsük ki hatványozással a műveleteket! Legyen egy új gomb az egyenlőség fölött x^y!
Köszönöm a figyelmet! Lazányi Kata kata.lazanyi@ponte.hu