praca z kontrolerami widoku tabeli w Swift
napisany przez Reinder de Vries dnia sierpnia 3 2020 w rozwój aplikacji, iOS
w tym samouczku pokażę Ci krok po kroku, jak działają Kontrolery widoku tabeli i jak można z nich korzystać. Przejdziemy do pełnej gamy UITableViewController
, zagłębiając się w programowanie obiektowe, delegację i zakulisowe mechanizmy widoków tabel.
kontroler widoku tabeli wyświetla uporządkowane, powtarzalne informacje w pionowej liście. Do tworzenia kontrolera widoku tabeli używasz klasy UITableViewController
w aplikacji na iOS.
praca z kontrolerem widoku tabeli oznacza również pracę z kilkoma ważnymi koncepcjami Rozwoju Systemu iOS, takimi jak podklasowanie, wzorzec projektowania delegacji i ponowne wykorzystanie widoków.
to ważne dla profesjonalnych i praktycznych programistów iOS (ty!) do opanowania pracy ze sterownikami widoku tabeli. Gdy już przyzwyczaisz się do pracy nad tak wielopłaszczyznowym komponentem UI, takim jak UITableViewController
, inne bardziej złożone aspekty rozwoju iOS zaczną mieć sens.
gotowy? Zanurzmy się!
- jak działa kontroler widoku tabeli
- Konfigurowanie prostego kontrolera widoku tabeli
- kodowanie źródła danych kontrolera widoku tabeli
- dostarczanie komórek do kontrolera widoku tabeli
- reagowanie na interakcje użytkownika
- Czytaj dalej
jak działa kontroler widoku tabeli kontroler widoku działa
jeśli używałeś wcześniej dowolnej aplikacji na iOS, wcześniej używałeś kontrolerów widoku tabeli. Są one używane tak często w aplikacjach na iOS!
oto przykład kontrolera widoku tabeli:
kontroler widoku tabeli zwykle ma te widoczne komponenty:
- widok tabeli, który jest komponentem interfejsu użytkownika, lub widok, który jest wyświetlany na ekranie. Widok tabeli jest instancją klasy
UITableView
, która jest podklasąUIScrollView
. - komórki widoku tabeli, które są powtarzalnymi wierszami lub widokami, pokazanymi w widoku tabeli. Komórka widoku tabeli jest instancją klasy
UITableViewCell
i ta klasa jest często podklasowana do tworzenia niestandardowych komórek widoku tabeli.
kontroler widoku tabeli również opiera się na wykorzystaniu tych komponentów, Za kulisami:
- delegat widoku tabeli, który odpowiada za zarządzanie układem widoku tabeli i reagowanie na zdarzenia interakcji z użytkownikiem. Delegat widoku tabeli jest instancją klasy
UITableViewDelegate
. - źródło danych widoku tabeli, które jest odpowiedzialne za zarządzanie danymi w widoku tabeli, w tym komórkami i sekcjami widoku tabeli. Źródłem danych jest instancja klasy
UITableViewDataSource
.
Kontroler nawigacyjny jest często używany w połączeniu z kontrolerem widoku tabeli, aby umożliwić nawigację między widokiem tabeli a kolejnymi kontrolerami widoku oraz aby wyświetlić pasek nawigacji nad widokiem tabeli.
najciekawszą częścią pracy z kontrolerami widoku tabeli jest sam kontroler widoku tabeli! Jak to?
czy znasz architekturę Model-View-Controller? Zgodnie z architekturą Model-View-Controller widok tabeli i komórka widoku tabeli są widokami,a kontroler widoku tabeli jest kontrolerem.
widoki są odpowiedzialne za wyświetlanie informacji w sposób widoczny dla użytkownika, z interfejsem użytkownika (UI). Administratorzy są odpowiedzialni za wdrażanie logiki, zarządzanie danymi i podejmowanie decyzji. Powiedział inaczej: nie widzisz kontrolera, ale on tam jest, zarządzając tym, co widzisz za pomocą widoków.
gdy używasz kontrolera widoku tabeli w aplikacji, podklasujesz klasę UITableViewController
. Klasa UITableViewController
jest podklasą UIViewController.
oto hierarchia klas przykładowego kontrolera widoku tabeli, który wyświetla informacje kontaktowe:
- instancja
ContactsTableViewController
- podklasy
UITableViewController
- podklasy
UIViewController
- podklasy
- podklasy
zgodnie z zasadami programowania obiektowego (OOP), gdy Klasa RaceCar
podklasy klasy Vehicle
, dziedziczy właściwości i funkcje tej klasy nadrzędnej, takie jak maxSpeed
i drive()
.
Klasa Vehicle
jest wtedy nazywana superklasą RaceCar
. Zasada ta nazywana jest dziedziczeniem.
Może być! Pomyśl o tym tak: aby kontroler widoku tabeli działał poprawnie, musisz odziedziczyć kilka kodów, więc nie musisz pisać całego kodu samodzielnie. Hierarchia klas i OOP służą do uporządkowania tego dziedziczenia.
możesz pracować z widokami tabeli bez użycia kontrolera widoku tabeli. Wystarczy dodać UITableView
do kontrolera widoku, dostarczyć mu implementacje funkcji delegata widoku tabeli i źródła danych i gotowe.
Klasa UITableViewController
zapewnia domyślne implementacje tych funkcji delegowania widoku tabeli i źródła danych widoku tabeli. To kluczowy aspekt pracy z kontrolerem widoku stołu!
jak zobaczysz w kolejnych rozdziałach tego samouczka, nadpisamy te funkcje za pomocą naszych własnych implementacji. W ten sposób możemy dostosować kontroler widoku tabeli.
dowiedz się, jak tworzyć aplikacje na iOS
rozpocznij pracę z iOS 14 i Swift 5
Zapisz się na mój kurs programowania na iOS i dowiedz się, jak tworzyć świetne aplikacje na iOS 14 za pomocą Swift 5 i Xcode 12.
Konfigurowanie prostego kontrolera widoku tabeli
w porządku, wykorzystajmy to wszystko w praktyce. W tej sekcji zbudujemy prosty kontroler widoku tabeli. Zaimplementujesz funkcje potrzebne do działania, a ja wyjaśnię, jak działają. Ruszajmy!
możesz używać 3 różnych metod pracy z interfejsem użytkownika w Xcode:
- tworzenie widoków programowo, tj. kodowanie ich ręcznie
- Konfigurowanie Ui w Interface Builder i łączenie ich z kodem Swift za pomocą XIBs
- Konfigurowanie UI i ich przejść w Interface Builder za pomocą Storyboardów
- (technicznie można użyć SwiftUI też, ale jeśli chodzi o Kontrolery widoku tabeli, to poza zakresem tego samouczka.)
ręczne kodowanie UI jest żmudne i bezproduktywne. Jeśli nie jesteś ostrożny z Storyboardami, ukrywają one złożoność przed programistą. Będziemy pracować z Storyboardami, zastanawiając się dokładnie, jak działają za kulisami.
oto, co zamierzasz zrobić:
najpierw Utwórz nowy projekt Xcode za pomocą pliku → Nowy → Projekt…. Pamiętaj, aby wybrać szablon aplikacji i wybrać Storyboard dla interfejsu i delegat aplikacji UIKit dla cyklu życia.
następnie wykonaj następujące kroki:
- kliknij prawym przyciskiem myszy swój projekt w Nawigatorze projektu i wybierz nowy plik…
- Wybierz szablon klasy Cocoa Touch (iOS)
- Wybierz
UITableViewController
dla podklasy - Nazwij klasę
ContactsTableViewController
- nie zaznaczaj również Utwórz plik XIB
- wreszcie, kliknij Dalej i zapisz plik wraz z innymi plikami SWIFT
na koniec zrób to:
- przejdź do
Main.storyboard
i usuń istniejącą scenę kontrolera widoku - Dodaj nowy kontroler widoku tabeli do storyboardu za pomocą biblioteki
- Po wybraniu kontrolera widoku tabeli przejdź do Inspektora atrybutów i zaznacz pole wyboru is Initial View Controller
- na koniec przejdź do Inspektora tożsamości i ustaw klasę na
ContactsTableViewController
to jest to! Masz teraz kontroler widoku tabeli wewnątrz storyboardu projektu i podłączyłeś go do klasy ContactsTableViewController
Swift.
jak się domyślasz, twoja klasa ContactsTableViewController
jest podklasą UITableViewController
. Możesz to zobaczyć w pliku Swift, na górze, w deklaracji klasy.
class ContactsTableViewController: UITableViewController { ···
ta składnia oznacza: Klasa ContactsTableViewController
jest podklasą UITableViewController
.
po kliknięciu prawym przyciskiem myszy na „UITableViewController”, trzymając klawisz Option-key, możesz zobaczyć w deklaracji klasy, że UITableViewController
jest podklasą UIViewController
i jest zgodna z protokołami UITableViewDelegate
i UITableViewDataSource
.
to jest moc kontrolera widoku tabeli! To nie tylko daje nam poszczególne komponenty do tworzenia widoku tabeli, kontroler zapewnia również domyślną implementację. Dlatego podklasa UITableViewController
zamiast tworzyć pusty kontroler widoku z widokiem tabeli.
w tym momencie możesz uruchomić aplikację za pomocą Command-R
lub przycisku Odtwórz, a na ekranie pojawi się pusty kontroler widoku tabeli.
a tak w ogóle to czemu? Jeszcze nic nie zakodowaliśmy! Dzieje się tak dlatego, że kontroler widoku tabeli ma domyślną implementację, która po prostu pokazuje puste komórki na ekranie. Super!
w zależności od wersji Xcode użyliśmy delegata sceny do skonfigurowania początkowego kontrolera widoku projektu aplikacji. Dowiedz się więcej tutaj: Delegat sceny w Xcode
XIB i stalówka to w zasadzie to samo-zawierają informacje o układzie. XIB ma format XML, podczas gdy stalówka ma format binarny. XML jest kompilowany do binarnego podczas tworzenia aplikacji, dlatego funkcje UIKit zawsze mówią o „stalówce”, podczas gdy Xcode zawsze nazywa to „xib”.
kodowanie źródła danych kontrolera widoku tabeli
teraz, gdy twój kontroler widoku tabeli został skonfigurowany, ożyw go! W tym rozdziale skupimy się na różnych funkcjach, które musisz zaimplementować, aby kontroler widoku tabeli działał.
jak wyjaśniono wcześniej, funkcje te należą do delegata kontrolera widoku tabeli lub do źródła danych kontrolera widoku tabeli. Oba te protokoły używają delegacji, aby dostosować widok tabeli.
najważniejsze funkcje dla UITableViewDataSource
to:
numberOfSections(in:)
tableView(_:numberOfRowsInSection:)
tableView(_:cellForRowAt:)
inne istotne funkcje dla UITableViewDelegate
to:
tableView(_:didSelectRowAt:)
tableView(_:willDisplay:for:)
więcej funkcji można znaleźć w dokumentacji Apple Developer dla UITableViewDelegate i UITableViewDataSource.
Dodawanie danych kontaktów
rozpocznij od dodania danych kontaktowych kontrolera widoku tabeli. Dodaj następującą właściwość do klasy ContactsTableViewController
:
let contacts:] = , , , , , , , , , , , , , , , , ]
to rolodex, który wszyscy chcielibyśmy mieć, prawda? Oto jak to działa:
-
let contacts
deklaruje stałą o nazwiecontacts
. Dodałeś ją jako właściwość do klasy, więc każda instancja klasy ma dostęp do tej stałej w całym kodzie klasy. - Typ
contacts
to]
, czyli tablica tablic ciągów znaków. Zasadniczo tworzysz tablicę, której elementy są tablicami łańcuchów. (Nazwa zmiennej i jej Typ są oddzielone dwukropkiem:
) - kod
=
przypisuje literał tablicy docontacts
, wypełniony nazwiskami i numerami telefonów kilku miliarderów.
w późniejszym momencie możemy użyć liczby pozycji w tablicy z contacts.count
. I możemy uzyskać indywidualne nazwy i numery telefonów z contacts
i contacts
, używając składni indeksu dolnego.
rejestrowanie klasy komórek widoku tabeli
zanim będzie można używać komórek w kontrolerze widoku tabeli, należy je zarejestrować w widoku tabeli. Można to zrobić na dwa sposoby:
- podając klasę komórki widoku tabeli i identyfikator
- podając komórkę widoku tabeli XIB i identyfikator
gdy używasz niestandardowej komórki widoku tabeli, najprawdopodobniej chcesz zarejestrować XIB w tym celu. Gdy używasz domyślnych komórek widoku tabeli lub innej komórki programowej, rejestrujesz klasę. Na razie skorzystamy z zajęć!
Dodaj następujący kod do funkcji viewDidLoad()
:
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cellIdentifier")
upewnij się, że dodałeś go poniżej linii super.viewDidLoad()
. Jak zapewne wiesz, funkcja viewDidLoad()
jest częścią cyklu życia kontrolera widoku i należy do klasy UIViewController
.
nadpisujesz funkcję viewDidLoad()
, aby reagować na to zdarzenie w cyklu życia kontrolera widoku, dzięki czemu możesz skonfigurować Widok po jego załadowaniu. W naszym przypadku używamy funkcji do rejestracji komórki widoku tabeli.
podczas rejestracji komórki widoku tabeli musisz również podać identyfikator. Jest to po prostu kojarzenie klasy komórki z nazwą, której możesz użyć później, podczas usuwania komórki w tableView(_:cellForRowAt:)
.
jesteś jeszcze ze mną? Ruszajmy dalej!
implementacja „numberOfSections (in:)”
pierwszą funkcją delegata, którą zamierzamy zaimplementować, jest numberOfSections(in:)
.
widok tabeli może mieć wiele sekcji lub grup. Każda grupa ma nagłówek, który unosi się na górze pionowego rzędu komórek. W aplikacji Kontakty można grupować kontakty Alfabetycznie. W rzeczywistości odbywa się to w aplikacji Kontakty na iPhonie, gdzie kontakty są grupowane od A do Z.
aplikacja, którą tworzymy, ma tylko jedną sekcję. Dodaj następującą funkcję do klasy:
override func numberOfSections(in tableView: UITableView) -> Int{ return 1}
proste, prawda? Funkcja zwraca 1
po wywołaniu.
implementacja „tableView(_:numberOfRowsInSection:)”
podobną funkcją jest tableView(_:numberOfRowsInSection:)
. Zamiast podawać liczbę sekcji, podaje liczbę wierszy w sekcji. Ponieważ widok tabeli pokazuje komórki na liście pionowej, każda komórka odpowiada wierszowi w widoku tabeli.
aplikacja, którą tworzymy, ma tylko jedną sekcję, a ta sekcja ma liczbę elementów równą liczbie elementów w tablicy contacts
. Czyli contacts.count
!
dodaj następującą funkcję do klasy:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{ return contacts.count}
widzisz, jak to działa? Po prostu zwracamy contacts.count
. Jeśli miałbyś dodać inne imię i numer telefonu do contacts
, to też byłoby ładnie w widoku tabeli.
zrozumienie wierszy i sekcji
nasza aplikacja kontaktów jest jednowymiarowa, pokazuje tylko jedną listę nazwisk i numerów telefonów i nie używa grup. Ale co, jeśli masz pogrupowany widok tabeli?
w większości przypadków twoje źródło danych, takie jak tablica contacts
, również byłoby wielowymiarowe. Organizujesz grupy na pierwszym poziomie, a poszczególne elementy na drugim poziomie, „poniżej” grup.
- Countries - A - Afghanistan - Albania - ... - B - Bahamas - Bahrain - ... - C - Cambodia - Cameroon - ...
liczba grup jest równa countries.count
, a liczba krajów w jednej grupie jest równa countries.count
, gdzie x
to indeks sekcji. Ten indeks sekcji jest podany jako parametr w tableView(_:numberOfRowsInSection:)
.
czy zauważyłeś, że te dwie funkcje mają parametr o nazwie tableView
? To część zasady programowania obiektowego. Technicznie można użyć źródła danych widoku tabeli i delegować, aby dostosować wiele widoków tabeli. Używasz tableView
, aby określić, z którym widokiem tabeli pracujesz.
wyobraź sobie, że masz aplikację do kontaktów, która może wyświetlać numery telefonów po imieniu lub numery telefonów zorganizowane przez firmę. Można to zaimplementować na wiele sposobów, na przykład przez ponowne użycie kontrolerów widoku tabeli. A jeśli chcesz ponownie użyć układu aplikacji Kontakty, aby wyświetlić podobne informacje, takie jak restauracje, lokale lub nazwy użytkowników Skype ’ a? Tutaj pojawia się ponowne użycie kodu z OOP!
dostarczanie komórek do kontrolera widoku tabeli
jesteśmy na miejscu! Przejdźmy do najważniejszej funkcji kontrolera widoku tabeli: tableView(_:cellForRowAt:)
.
zaimplementujemy tę funkcję przed zagłębianiem się w szczegóły, ale jest kilka rzeczy, które musisz zrozumieć:
- gdy nazywa się
- co to jest ścieżka indeksu
- jak ponownie wykorzystuje komórki
najpierw dodaj następującą funkcję do klasy ContactsTableViewController
:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{}
oto jak to działa:
- funkcja nadpisuje swoją implementację klasy nadrzędnej z
UITableViewController
. Wiesz już, jak to działa, prawda? Nadpisujemy domyślną implementację i zastępujemy własną. To dlatego, żeUITableViewController
już zaimplementował delegat widoku tabeli i źródło danych dla nas. - podobnie jak poprzednio, funkcja ma jeden parametr
tableView
, którego możemy użyć do identyfikacji widoku tabeli, w którym ta funkcja jest wywoływana. - innym parametrem jest
indexPath
, z etykietą argumentucellForRowAt
. Ścieżka indeksu identyfikuje indeksyrow
isection
komórki. Więcej o tym później. - Typ zwrotu funkcji to
UITableViewCell
. To interesujące. Ta funkcja jest wywoływana przez kontroler widoku tabeli, za każdym razem, gdy potrzebujemy dostarczyć komórkę widoku tabeli!
podczas przewijania kontaktów w tej aplikacji za każdym razem, gdy komórka musi być wyświetlona na ekranie, wywoływana jest funkcja tableView(_:cellForRowAt:)
. Za każdym razem! Zaraz ci to udowodnię.
następnie napiszmy ciało funkcji. Dodaj następujący kod wewnątrz funkcji:
let cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifier", for: indexPath)print("\(#function) --- section = \(indexPath.section), row = \(indexPath.row)")cell.textLabel?.text = contactsreturn cell
oto co się dzieje:
- najpierw usuwamy komórkę z identyfikatorem. To dokładnie ten sam IDENTYFIKATOR, którego użyliśmy podczas rejestracji komórki. W ten sposób Widok tabeli wie, jakiego typu komórki chcemy. Odłączona komórka jest przypisana do stałej
cell
. Teraz mamy komórkę widoku tabeli do pracy. Więcej o dequeuingu później. - następnie drukujemy pewne informacje na konsolę. To jest tak, że możemy zobaczyć, kiedy ta funkcja jest wywoływana, kiedy aplikacja działa.
- następnie przypisujemy nazwę kontaktu do etykiety tekstowej tej komórki widoku tabeli.
contacts
zawiera wartość nazwy Kontaktu, do której docieramy używającindexPath.row
. Każda instancjaUITableViewCell
ma właściwośćtextLabel
UILabel
, a każda etykieta tego typu ma właściwośćtext
. Służy do ustawiania tekstu na etykiecie.
nie martw się, omówimy każdą z tych rzeczy bardziej szczegółowo. Najpierw sprawdź, czy możesz uruchomić aplikację. Widzisz nazwiska kontaktów? Czy widzisz wyjście debugowania w konsoli? Spróbuj przewijać aplikację!
kiedy nazywa się „tableView(_:cellForRowAt:)”?
jeśli uruchomiłeś aplikację Kontakty i bawiłeś się przewijaniem w górę i w dół, nie możesz nie zauważyć, że za każdym razem, gdy przewijasz, dane wyjściowe debugowania pojawiają się w konsoli.
za każdym razem, gdy pojawia się komórka, która wcześniej nie była na ekranie, wywoływana jest funkcja tableView(_:cellForRowAt:)
i pojawia się nowa linia w konsoli.
kiedy dzwoni tableView(_:cellForRowAt:)
? Za każdym razem, gdy komórka widoku tabeli musi być wyświetlana na ekranie!
kontroler widoku tabeli określił, że komórka jest potrzebna, więc wywołuje tableView(_:cellForRowAt:)
. Nasza implementacja tej funkcji usuwa komórkę, zmienia ją i dostarcza z powrotem do kontrolera widoku tabeli. Kontroler widoku tabeli i framework UIKit renderują go graficznie na ekranie.
co to jest ścieżka indeksu?
za każdym razem, gdy kontroler widoku tabeli potrzebuje komórki z tableView(_:cellForRowAt:)
, podaje ścieżkę indeksu jako argument dla funkcji. W treści funkcji można użyć parametru indexPath
, aby dokładnie wiedzieć, której komórki potrzebuje kontroler widoku tabeli.
ścieżka indeksu jest jak adres lub współrzędna w siatce. Typowy Wykres ma oś X i oś Y, więc można wyrazić współrzędną na tym wykresie jako x, y
, jak 0, 1
i 42, 3
. Podobnie, arkusz kalkulacyjny ma wiersze i kolumny z indeksami.
widok tabeli używa sekcji i wierszy. Jak wspomniano wcześniej, możesz użyć sekcji do grupowania komórek razem. Nasza aplikacja ma tylko jedną sekcję i ma contacts.count
wiersze. Wiersze widoku tabeli przebiegają od góry do dołu.
powiedział inaczej: sekcje i wiersze widoku tabeli są tym, czym kolumny i wiersze są w arkuszu kalkulacyjnym. Ścieżka indeksu definiuje lokalizację w widoku tabeli, używając wiersza i sekcji.
wiersze i sekcje są reprezentowane przez liczby, zwane indeksami. Indeksy te zaczynają się od zera, więc pierwszy wiersz i sekcja będą miały Numer indeksu 0
.
kiedy spojrzysz wstecz na poprzedni zrzut ekranu, ma to o wiele większy sens. Pierwsza komórka ma ścieżkę indeksu 0, 0
, druga komórka 0, 1
, kontynuując do ostatniej widocznej komórki ze ścieżką indeksu 0, 11
.
mechanizm ponownego wykorzystania widoku tabeli
najbardziej godny uwagi jest mechanizm ponownego wykorzystania komórek w widoku tabeli. To całkiem proste.
- za każdym razem, gdy kontroler widoku tabeli musi pokazać komórkę na ekranie, wywoływana jest funkcja
tableView(_:cellForRowAt:)
, jak już omówiliśmy wcześniej. - zamiast tworzyć nową komórkę widoku tabeli za każdym razem, gdy ta funkcja jest wywoływana, pobiera wcześniej utworzoną komórkę z kolejki.
- komórka resetuje się do stanu pustego, usuwa jej wygląd, a komórka jest ponownie dostosowywana w
tableView(_:cellForRowAt:)
. - gdy komórka jest przewijana poza ekran, nie jest niszczona. Jest dodawany do kolejki, czekając na ponowne użycie.
to całkiem sprytne, prawda? Zamiast tworzyć i usuwać komórki, po prostu używasz ich ponownie. Ale … dlaczego?
ponowne wykorzystanie komórek jest znacznie mniej intensywne. Kontroler widoku tabeli stale zapisywał do pamięci podczas tworzenia i usuwania komórek. Zarządzanie pamięcią byłoby również bardziej intensywne. Gdy komórki są ponownie używane, pamięć jest używana wydajniej i potrzeba mniej operacji na pamięci.
ponadto ITT jest nieco mniej obciążony procesorem, aby ponownie używać komórek zamiast ich tworzyć i usuwać, ponieważ po prostu jest mniej operacji związanych z ponownym użyciem w porównaniu z tworzeniem i usuwaniem komórek.
gdy szybko przewijasz widok tabeli, nie widzisz nowych komórek – widzisz te same komórki w kółko, z nowymi informacjami.
kod związany z ponownym użyciem komórki jest następujący:
let cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifier", for: indexPath)
funkcja dequeueReusableCell(withIdentifier:)
próbuje oddzielić komórkę. Gdy nie ma komórek w kolejce, utworzy dla nas komórkę. Identyfikator jest używany do przechowywania każdego typu komórki w ich własnej kolejce i aby upewnić się, że odpowiednia klasa jest używana do tworzenia nowych komórek.
dowiedz się, jak tworzyć aplikacje na iOS
rozpocznij pracę z iOS 14 i Swift 5
Zapisz się na mój kurs programowania na iOS i dowiedz się, jak tworzyć świetne aplikacje na iOS 14 za pomocą Swift 5 i Xcode 12.
reagowanie na interakcję z użytkownikiem
w naszym kontrolerze widoku tabeli brakuje jednej rzeczy: możliwości dzwonienia do osób z naszej listy kontaktów! Ale zanim to zrobimy, upewnijmy się, że możesz również zobaczyć numer telefonu kontaktu w kontrolerze widoku tabeli.
domyślna klasa UITableViewCell
ma 4 różne typy, wyrażone w wyliczeniu UITableViewCellStyle
. Możesz wybrać pomiędzy:
-
.default
– prosty widok z jedną linią czarnego tekstu -
.value1
– prosty widok z jedną linią czarnego tekstu po lewej stronie i małą niebieską etykietą po prawej stronie (używaną w aplikacji Ustawienia) -
.value2
– prosty widok z jedną linią czarnego tekstu po prawej stronie i małą niebieską etykietą po lewej stronie (używaną w aplikacji Kontakty) -
.subtitle
– prosty widok z jedną linią czarnego tekstu i mniejszą linią szarego tekstu pod nim
większość programistów używa niestandardowych komórek widoku tabeli w dzisiejszych czasach, więc nie zobaczysz tych typów komórek tak często. Ale oni tam są!
musimy nieco dostosować kod w tableView(_:cellForRowAt:)
. Zastąp pierwszą linię funkcji następującym kodem:
var cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifier")if cell == nil{ cell = UITableViewCell(style: .subtitle, reuseIdentifier: "cellIdentifier")}
jeśli przyjrzysz się bliżej, zobaczysz, że usunęliśmy część for: indexPath
wywołania dequeueReusableCell(...)
. Zamiast tego funkcja ta zwraca teraz opcjonalne. Gdy nie może usunąć komórki, funkcja zwraca nil
.
następnie wskakujemy do siebie, aby utworzyć komórkę, jeśli jest to nil
. Widzisz to w drugiej części kodeksu. Aby sprawdzić, czy cell
jest równe nil
, należy użyć polecenia warunkowego if
, a jeśli to prawda, utworzyć komórkę za pomocą inicjatora UITableViewCell(style:reuseIdentifier:)
.
inicjalizator otrzymuje dwa argumenty, styl komórki .subtitle
i identyfikator, którego użyliśmy wcześniej.
w tym momencie mamy problem, bo cell
jest teraz opcjonalne! Jego typ to UITableViewCell?
, ale funkcja return type wymaga, abyśmy zwrócili instancję z nieobowiązkowym typem UITableViewCell
.
na szczęście jest to jeden z tych przypadków, w których możemy bezpiecznie użyć siły rozpakowywania, aby rozpakować wartość opcjonalną. Ze względu na sposób pisania naszego kodu, cell
nie może być nil
poza trybem warunkowym. Możesz zagwarantować, że cell
nie jest nil
po instrukcji if
.
upewnij się, że zaktualizowałeś funkcję, aby użyć siły rozpakowywania dla cell
. Dodaj również poniższy wiersz kodu poniżej cell!.textLabel ...
, aby ustawić podtytuł komórki pokaż numer telefonu kontaktu.
cell!.detailTextLabel?.text = contacts
cała funkcja wygląda teraz tak:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{ var cell = tableView.dequeueReusableCell(withIdentifier: "cellIdentifier") if cell == nil { cell = UITableViewCell(style: .subtitle, reuseIdentifier: "cellIdentifier") } print("\(#function) --- section = \(indexPath.section), row = \(indexPath.row)") cell!.textLabel?.text = contacts cell!.detailTextLabel?.text = contacts return cell!}
na koniec upewnij się, że usuniesz poniższą linię z viewDidLoad()
. Zapobiegnie to inicjalizacji komórek niewłaściwego typu w widoku tabeli.
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "cellIdentifier")
Uruchom aplikację za pomocą polecenia + R lub przycisku Odtwórz i sprawdź, czy działa. Widzisz nazwiska i numery telefonów? Dobrze!
następnie, dla pièce-de-résistance, dodajmy tę funkcję interakcji użytkownika. Teraz, gdy nauczyłeś się zawiłości kontrolera widoku tabeli, myślę, że już wiesz, jak działa ta następna funkcja.
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){ if let url = URL(string: "tel://" + contacts) { UIApplication.shared.open(url) }}
ponownie nadpisujemy domyślną implementację funkcji tableView(_:didSelectRowAt:)
. Funkcja ta jest wywoływana, gdy użytkownik dotknie komórki widoku tabeli i należy do protokołu UITableViewDelegate
. Podobnie jak inne funkcje, zapewnia ścieżkę indeksu komórki, która jest podsłuchiwana.
w ciele funkcji po prostu tworzymy tel://
URL z numeru telefonu. Następnie powiemy aplikacji, aby otworzyła ten adres URL, co skutecznie powie iOS, aby zainicjował połączenie na ten numer. Ten kod jest tam tylko w celach poglądowych. Zauważ, że to nie działa na symulatorze iPhone ’ a, a liczby w naszej aplikacji są fałszywe. (Mimo to, można użyć tego kodu, jeśli robisz prawdziwe kontakty aplikacji!)
możesz dodać następujący kod do funkcji, jeśli chcesz sprawdzić, czy działa dobrze.
print("\(#function) --- Calling: \(contacts)")
po dotknięciu komórki widoku tabeli wyświetli się komunikat debugowania.
Czytaj dalej
i to wszystko! To była niezła podróż, ale teraz wiesz, jak działa kontroler widoku stołu.