Skocz do zawartości

Witaj!

Zaloguj lub Zarejestruj się aby uzyskać pełny dostęp do forum.

Zdjęcie
- - - - -

Programowanie na iPhone [Cz. 4 - Widok tabeli]


  • Zaloguj się, aby dodać odpowiedź
9 odpowiedzi w tym temacie

#1 zbiju

zbiju
  • 34 postów

Napisano 03 października 2009 - 15:25

Dołączona grafika

Widok tabeli to chyba jeden z najczęściej używanych komponentów dostarczanych wraz z SDK. Nic dziwnego, bo to bardzo przydatny i użyteczny twór. Dziś spróbujemy się do niego dobrać i stworzyć prostą listę zakupów. Przy okazji dowiemy się conieco jak korzystać z Interface Buildera oraz jak tworzyć widoki bez jego użycia. Plan jest następujący:

  • Stworzyć nowy projekt
  • Stworzyć widok do dodawania elementów do listy
  • Pokazać listę zakupów
  • Zapisać listę podczas zamykania aplikacji
  • Odczytać listę podczas uruchamiania aplikacji
  • Usuwać elementy z listy
Do dzieła.


Zaczynamy naturalnie od stworzenia nowego projektu, tym razem wybieramy jako jego typ "Navigation-based Application". W naszym programie co prawda nie będzie zbyt wiele nawigacji ponieważ będziemy mieli tylko jeden widok, ale wybierając ten typ będziemy mieli przygotowane już bardzo wiele. Wybieramy jakąś nazwę projektu i możemy cieszyć nasze oczy widokiem... no cóż, niezbyt wiele widać po skompilowaniu projektu na tym etapie.

Dołączona grafika
Typ projektu


Do naszej dyspozycji dostaliśmy już gotowy obiekt nawigatora, który służy do pokazywania i ukrywania wszelkiem maści widoków. Zapamiętuje też w jakiej kolejności te widoki były pokazywane na ekranie, co znacznie ułatwia powrót do poprzedniego ekranu. Dziś nie będziemy się tym zajmować szczegółowo. Dostaliśmy również przygotowaną tabelę, która jest nieco upośledzona, bo ma tylko jedną kolumnę, ale to w zupełności wystarczy.

RootViewController został przygotowany w taki sposób, aby był też źródłem danych dla naszej tabeli. Jest też delegatem naszej tabeli, więc dostaliśmy zestaw 3 w 1. W bardziej rozbudowanych aplikacjach kontroler niekoniecznie pełni wszystkie te role naraz. Dostalibyśmy wtedy przerośniętą klasę do wszystkiego, a nie o to chodzi.

W skład projektu wchodzą też dwa pliki xib. Jeden obrazuje tabelę (RootViewController.xib) i nie będziemy go modyfikować. Zmienimy nieco MainWindow.xib. Klikamy 2 razy na tym pliku aby go otworzyć w Interface Builderze. Zmieńmy tytuł na coś bardziej informatywnego niż pusty ciąg znaków. Klikamy dwa razy mniej więcej na środku paska nawigacji i wpisujemy co się nam podoba. Oczywiście żadne elaboraty się tam nie zmieszczą. Ja wpisałem po prostu "Lista zakupów".

Dołączona grafika
Zmieniamy tytuł


Skoro już mamy otwarty IB dodajmy sobie po prawej stronie nawigacji przycisk do dodawania nowych elementów listy. Przeciągamy "Bar Button Item" i zmieniamy mu tytuł na "Dodaj". Na razie jeszcze nie zamykamy IB. Przycisk powinien coś robić, w naszym przypadku po kliknięciu (tapnięciu?) będzie się pojawiać małe okienko do wpisania nazwy nowego elementu listy i jego zatwierdzenia. Wracamy na moment do XCode i w RootViewController.h dodajemy nową metodę showAddView oznaczoną jako IBAction. Zapisujemy i wracamy do IB na moment, żeby połączyć przycisk z tą nową metodą. W tym celu zaznaczamy przycisk i z inspektora połączeń przeciągamy aż do okienka z informacjami o dokumencie na RootViewController. Powinno pojawić się małe okienko z wyborem metod na jakie możemy ustawić akcję przycisku. Ponieważ mamy tylko jedną, nie ma się nad czym zastanawiać.

Dołączona grafika
Wybieramy komponent z listy

Dołączona grafika
Przeciągamy na pasek nawigacji

Dołączona grafika
Dodajemy metodę do kontrolera

Dołączona grafika
Łączymy przycisk z akcją


Na razie możemy wyłączyć Interface Builder, ale później jeszcze do niego wrócimy. Stworzyliśmy tylko deklarację metody, ale jeszcze nic nie robi. Gdybyśmy teraz spróbowali skompilować projekt dostalibyśmy informację o tym, że klasa nie jest skończona. Przechodzimy do RootViewController.m i gdzieś na końcu lub gdziekolwiek nam pasuje, dopisujemy naszą metodę. Stworzymy teraz widok dodawania nowego elementu listy zakupowej. Skorzystamy z istniejącego już UIAlertView, który generalnie służy do pokazywania komunikatów wszelkiej maści, ale dzięki małemu trikowi rozszerzymy nieco jego funkcjonalność. Przy się też odwołanie do komponentu tekstowego, więc jeszcze tylko szybko go dodajmy i się zabieramy do poważniejszego kodowania. W pliku nagłówkowym dodajemy nową własność do klasy, a w pliku implementacji korzystamy z dobrodziejstw @synthesize. Dzięki temu zabiegowi będziemy mieli stworzone funkcje dostępu do tej zmiennej (getter i setter).

Dołączona grafika
Dodajemy nową własność

Dołączona grafika
Implementacja showAddView:


Po kolei co się tutaj dzieje. Tworzymy nowy UIAlertView z tytułem i przyciskami. Nie zapomnijmy dodać "nil" tuż przed ostatnim nawiasem kwadratowym. Informuje on inicjalizator, że skończyła się już lista dodatkowych przycisków. Następnie sprawdzamy czy nasz UITextField było już wcześniej tworzone, jeśli tak to zwalniamy go z pamięci i tworzymy nowy. Liczby podawane podczas jego tworzenia to pozycja w nadrzędnym widoku (pierwsze para) oraz wielkość elementu (druga para). Dodajemy do naszego alertu i moglibyśmy już w tym momencie wywołać metodę show, ale powstałby mały problem. Klawiatura zasłoniłaby przyciski alertu i ciężko byłoby coś zrobić. Dlatego dodajemy transformację, aby przesunąć widok wyżej. Teraz możemy już pokazać widok i zwolnić go z pamięci tuż po.


Dołączona grafika
Zasłonięty alert


Na tym etapie mamy już możliwość wpisywania elementów listy, ale co z tego skoro nic się z nimi nie dzieje. Wspomniałem wcześniej, że kontroler jest jednocześnie źródłem danych tabeli, ale jeśli przygładaliście się, co w jego kodzie się znajduje to na pewno zauważyliście, że źródło danych jest puste. Dodajmy więc tablicę NSMutableArray, która będzie służyć jako kontener listy. Dopisujemy ją podobnie jak wcześniej UITextField.

Jako delegata naszego widoku dodawania (przypominam UIAlertView) ustawiliśmy aktualny obiekt, a więc RootViewContoller. Delegat to obiekt, który dostaje informacje o zdarzeniach związanych z innym obiektem i powinien te zdarzenia obsłużyć. My chcielibyśmy wiedzieć, co użytkownik chce dodać do listy. W tym celu musimy zaimplementować metodę "alertView:clickedButtonAtIndex:".

http://iphone.devzon...003a-300x58.png
Implementacja clickedButtonAtIndex:


Nic skomplikowanego tutaj nie mamy. Sprawdzamy tylko czy użytkownik wcisnął przycisk "OK" i jeśli tak, to dopisujemy do tablicy nowy string i przeładowujemy tabelę. Musimy to zrobić ponieważ źródło danych się zmieniło. Reszta to usuwanie UITextView z nadrzędnego widoku oraz chowanie alertu. W tym momencie możecie się natknąć na trzy problemy. Jeden to niezainicjalizowana tablica. Na razie możecie stworzyć ją pustą gdzieś w "loadView". Drugi problem to nadal pusta tabela. Dzieje się tak dlatego, że metoda odpowiedzialna za to, żeby powiedzieć kontrolerowi ile jest wierszy w tabeli cały czas zwraca 0. Powinniśmy to zmienić tak, aby zwracała liczbę elementów tablicy. Ostatni problem to puste komórki tabeli, nie zawierają żadnego tekstu. Aby to zmienić szukamy metody "tableView:tableView cellForRowAtIndexPath:" i dodajemy linijkę przypisującą tekst z tablicy do etykiety komórki.

http://iphone.devzon...z010-300x54.png
Inicjalizacja tablicy

http://iphone.devzon...z012-300x31.png
Ilość wierszy tabeli

http://iphone.devzon...z014-300x28.png
Ustawiamy zawartość komórek tabeli


Na tym etapie powinniśmy mieć wyświetloną listę zakupów. Nie jest ona zbyt użyteczna, bo gdy wyłączymy i włączymy program ponownie, lista będzie pusta. Musimy ją zapisać. Proponuję zrobić to podczas zamykania programu. Przechodzimy do pliku, którego nazwa kończy się na AppDelegate.m, w moim przypadku to TableViewTutorialAppDelegate.m. Gdzieś w nim znajdziemy metodę "applicationWillTerminate:" i dodajemy kod do zapisu.

http://iphone.devzon...z015-300x22.png
Zapis tablicy do pliku


Te dwie linijki powinny same siebie opisywać :) Najpierw tworzymy string zawierający ścieżkę do pliku, chcemy żeby dane były zapisane wewnątrz naszej aplikacji w pliku o nazwie "shoppingList.plist". W drugiej linijce korzystamy z własności nawigatora, topViewController. Jest to kontroler widoku, który aktualnie pokazywany jest na ekranie. My mamy tylko jeden, więc zawsze będzie to ten odpowiedni. Następnie zapisujemy tablicę do pliku. Jeśli wcześniej taki plik istniał, zostanie on nadpisany.

Zapisaliśmy naszą listę zakupów, wypadałoby ją jeszcze odczytywać podczas uruchamiania programu. Wracamy w tym celu do RootViewController.m. Najlepszym miejscem na odczytanie listy będzie "loadView:", gdzie wcześniej inicjalizowaliśmy tablicę.

http://iphone.devzon...0011-300x76.png
Odczytujemy zapisaną listę


Widzimy tutaj znów ścieżkę do pliku. Następnie sprawdzamy czy taki plik faktycznie istnieje i w zależności od tego tworzymy obiekt tablicy. Nie było to nic trudnego.

Wybrałem taki sposób przechowywania danych wewnątrz aplikacji ponieważ listy zakupów zazwyczaj nie są bardzo długie. Nie musimy się przejmować czy wystarczy nam pamięci na jej przechowanie ani czy odczyt nie zajmie zbyt wiele czasu.

Okej, mamy naszą listę zakupów. Możemy pójść do sklepu i tym razem kupić wszystko, czego nam potrzeba. Jednak nie zawsze kupujemy dokładnie to samo, dodajmy więc możliwość usuwania elementów listy. Zanim otworzymy po raz ostatni Interface Builder, dorzućmy do naszego kontrolera deklarację dwóch akcji. Jedną z nich od razu wykorzystamy podczas dodawania nowego przycisku.

http://iphone.devzon...004-300x134.png
RootViewController.h


Otwieramy IB i dodajemy nowy przycisk po lewej stronie, zmieńmy mu nazwę na "Edytuj". Dodajemy do niego akcję "showEditing:". Pamiętacie jak? Przeciągamy od kropki przy "selector" aż do naszego kontrolera. Tyle nam wystarczy jeśli chodzi o IB. Wracam do XCode i dodajemy implementację powyższych metod. Będziemy ze sobą zamieniać tytuł przycisku oraz akcję do niego przypisana.

http://iphone.devzon...z016-300x89.png
Implementacja metod do przycisku edycji


Jedynym ciekawym fragmentem w obu z nich jest ustawianie tabeli w stan edycji. Już prawie jesteśmy na finishu. Odszukujemy gdzieś w naszym kodzie sprezentowaną nam przez szablon projektu metodę "tableView:commitEditingStyle:forRowAtIndexPath:". Może być zakomentowana. W części odpowiedzialnej za usuwanie dodajemy usuwanie elementu z naszej tablicy i to wszystko. Program gotowy.

http://iphone.devzon...0021-300x67.png
Usuwanie elementu z listy


Jako zadanie domowe spróbujcie dodać sortowanie elementów albo edycję w taki sposób, żeby nie trzeba było nic najpierw usuwać.

Gotowy projekt można pobrać stąd: http://iphone.devzon...iewTutorial.zip


Tekst pochodzi z mojego bloga iPhone z zaplecza.

#2 BartMax

BartMax
  • 39 postów

Napisano 04 października 2009 - 15:14

Czasami mam wrazenie, ze tylko ja wszystko robie programistycznie bez uzywania Interface Builder'a.

#3 iro88

iro88
  • 133 postów
  • SkądŚwidnica

Napisano 04 października 2009 - 15:25

Wydaje mi się, że po to on jest aby zaoszczędzić sobie pisania. Lecz umiejętność zrobienia tego samego co w Interface Builder za pomocą kodu bardzo się przydaje.

#4 feuerfest

feuerfest
  • 3 417 postów
  • SkądMonachium, DE

Napisano 04 października 2009 - 15:28

Ja sie chyba zainteresuje pisaniem appow na iphone zainspirowany tymi tutorialami :D

#5 zbiju

zbiju
  • 34 postów

Napisano 04 października 2009 - 18:51

Czasami mam wrazenie, ze tylko ja wszystko robie programistycznie bez uzywania Interface Builder'a.


hehe, nie tylko, IB sie przydaje, ale nie wszystko sie da zrobic przy jego pomocy

#6 BartMax

BartMax
  • 39 postów

Napisano 04 października 2009 - 19:02

Szczerze mowiac na samym poczatku mialem jakis problem z IB. Wiec zrobilem jedna appke tylko programistycznie(troche to zajelo). Teraz uzywam tylko kopiuj/wklej do poszczegolnych elementow, wiec czas wykonywnia interfejsu jest mniej wiecej taki sam.

#7 heretique

heretique
  • 334 postów
  • SkądKraków

Napisano 06 października 2009 - 21:42

Mówią niektórzy, że ładowanie interfejsu z NIB-ów jest powolne, więc tam gdzie miałoby się to odbywać bardzo często-gęsto, warto zmontować widok metodą czysto programistyczną.

#8 Grzela

Grzela
  • 950 postów
  • SkądWarszawa

Napisano 06 października 2009 - 21:59

Jako kompletny laik, byłem w stanie "zbudować" Hello Wrorld oraz TabBarHello. Niestety przy tym już wymiękam. Może mi ktoś powiedzieć jak mogę nauczyć się podstaw Objective C?

#9 iro88

iro88
  • 133 postów
  • SkądŚwidnica

Napisano 07 października 2009 - 07:25

Jako kompletny laik, byłem w stanie "zbudować" Hello Wrorld oraz TabBarHello. Niestety przy tym już wymiękam. Może mi ktoś powiedzieć jak mogę nauczyć się podstaw Objective C?


Cocoa Dev Central: Learn Objective-C

A tak poza tym to poszukaj czasem w google lub tu na forum, to nie boli.

#10 zbiju

zbiju
  • 34 postów

Napisano 07 października 2009 - 08:55

Jako kompletny laik, byłem w stanie "zbudować" Hello Wrorld oraz TabBarHello. Niestety przy tym już wymiękam. Może mi ktoś powiedzieć jak mogę nauczyć się podstaw Objective C?


w ktorym momencie sie gubisz?




Użytkownicy przeglądający ten temat: 1

0 użytkowników, 1 gości, 0 anonimowych