Hvordan lage en tabellvisning programmatisk?
La oss hoppe rett inn ikodingDel, men først: Start Xcode, lag et nytt iOS Single View App Project, skriv inn noen navn og detaljer for prosjektet som vanlig, bruk Swift og til slu*tt åpne ViewController.swift -filen med en gang.Ta nå tastaturet ditt!⌨
Pro -tips: Bruk CMD+Shift+O for å raskt hoppe mellom filer
Jeg skal ikke bruke grensesnittbygger i denne opplæringen, så hvordan lager vi visninger programmatisk?Det er en metode som heter LoadView som er der du bør legge til tilpassede visninger til ditt synshierarki.Du kan alternativ+klikke på metodenavnet i Xcode og lese diskusjonen omLoadViewMetode, men la meg oppsummere hele saken.
Vi bruker en svak egenskap for å holde en henvisning til tabellvisningen.Deretter overstyrer vi LoadView Method & Ring Super, for å laste inn kontrollerens Self.View -egenskap med et visningsobjekt (fra en nibb eller en storyboard -fil hvis det er en for kontrolleren).Etter det tildeler vi vår splitter nye visning til en lokal eiendom, slår av systemet som er gitt oppsett og setter inn tabellvisningen vår i vårt synshierarki.Til slu*tt lager vi noen reelle begrensninger ved hjelp av anker og lagrer pekeren vår til vår svake eiendom.Lett!🤪
klasseViewController:UIViewController{svak varTableView:UITableView!Overstyr FuncLoadView () {super.LoadView()laTableView =UITableView(ramme :.null, stil: .vanlig) TableView.OversattesautorisizingmaskIntoconstraints=Falske selv.utsikt.ADDSUBVIEW(TableView)Nslayoutconstraint.aktivere([selv-.utsikt.SafeareAlayOutguide.Topanchor.begrensning(Equalto: TableView.Topanchor),selv-.utsikt.SafeareAlayOutguide.Bottomanchor.begrensning(Equalto: TableView.Bottomanchor),selv-.utsikt.LEADINGANCHOR.begrensning(Equalto: TableView.LEADINGANCHOR),selv-.utsikt.Trailinganchor.begrensning(Equalto: TableView.Trailinganchor),])selv-.TableView= tableView}}
Bruk alltid automatisk layoutankere for å spesifisere visningsbegrensninger, hvis du ikke vet hvordan du bruker dem, sjekk minLayout Anchors Tutorial, Det tar bare omtrent 15 minutter å lære denne API -en, og du vil ikke angre.Det er et ekstremt nyttig verktøy for enhver iOS -utvikler!😉
Du kan spørre: Skal jeg brukesvak eller sterkEgenskaper for visningsreferanser?Jeg vil si i de fleste tilfeller at hvis du ikke overstyrer selv. Vis du bør bruke svakt!Visningshierarkiet vil holde din tilpassede visning gjennom en sterk referanse, så det er ikke behov for dumme støttesykluser og minnelekkasjer.Stol på meg!🤥
UITableViewDataSource Basics
Ok, vi har en tom tabellvisning, la oss vise noenceller!For å fylle tabellvisningen med ekte data, må vi samsvare med UITableViewDataSource -protokollen.Gjennom en enkeldelegatmønster, Vi kan gi forskjellige informasjon for UITableView -klassen, så det vil vite hvor mye seksjoner og rader som vil være nødvendig, hva slags celler som skal vises for hver rad og mange flere små detaljer.
En annen ting er at UITableView er en virkelig effektiv klasse.Det vil gjenbruke alle cellene som foreløpig ikke vises på skjermen, så det vil konsumere mindre minne enn en UiscrollView, hvis du må takle hundrevis eller tusenvis av gjenstander.For å støtte denne oppførselen må vi registrere celleklassen vår med en gjenbruksidentifikator, så det underliggende systemet vil vite hva slags celle som er nødvendig for et bestemt sted.⚙
klasseViewController:UIViewController{varElementer: [Streng] = ["👽","🐱","🐔","🐶","🦊","🐵","🐼","🐷","💩","🐰","🤖","🦄","🐻","🐲","🦁","💀","🐨","🐯","👻","🦖"]Overstyr FuncviewDidLoad () {super.ViewDidload()selv-.TableView.registrere(UITableViewCell.selv-, ForcellReuseIdentifier:"UITableViewcell")selv-.TableView.datakilde=selv-}}Utvidelse ViewController:UITableViewDataSource{funcTableView (_TableView:UITableView, NumberOfRowSSection Section:Int) ->Int{Returnerer selv.gjenstander.telle}funcTableView (_TableView:UITableView, Cellforrowat IndexPath:IndexPath) ->UITableViewCell{laCell = TableView.DequeueReusableCell(med identifisering:"UITableViewcell", for: IndexPath)lavare =selv-.gjenstander[IndexPath.punkt] celle.Tekstlabel?.tekst= varekomme tilbakecelle}}
Etter å ha lagt til noen få kodelinjer i vår visningskontrollerfil, kan tabellvisningen nå vise en fin liste over emojier!Vi bruker den innebygde UITableViewCell-klassen fra UIKIT, som er veldig nyttig hvis du er god til å gå med de "iOS-systemlignende" celledesignene.Vi samsvarte også med datakildeprotokollen, ved å fortelle hvor mange elementer som er i vår seksjon (for øyeblikket er det bare en seksjon), og vi konfigurerte cellen vår inne i den berømte cellen for rad på IndexPath -delegatmetoden.😎
Tilpasse tabellvisningsceller
UITableViewCell kan gi noen grunnleggende elementer for å vise data (tittel, detaljer, bilde i forskjellige stiler), men vanligvis trenger du spesialdesignede celler.Her er en grunnleggende mal for en tilpasset celle -underklasse, jeg skal forklare alle metodene etter koden.
klasseMycell:UITableViewCell{Overstyr init(stil:UITableViewCell.Cellstyle, gjenbruk:Streng?) {super.i det(Stil: Stil, gjenbrukidentifikator: gjenbrukidentifikator)selv-.Initialiser()}påkrevd init? (Koder Adecoder:Nscoder) {super.i det(Koder: Adecoder)selv-.Initialiser()}funcinitialiser () {}/ * Overstyring func awakeFromNib () {super.awakeFromNib ()} */ Overstyr Funcpreparreuse () {super.Forberedelse av()}}
Deinit (stil: gjenbrukidentifikator)
Metode er et flott sted å overstyre egenskapen til cellestil hvis du skal bruke standard UITableViewCell programmatisk, men med forskjellige stiler (det er ikke noe alternativ å angi cellestil etter at cellen ble initialisert).For eksempel hvis du trenger en.value1
Stylet celle, bare gi argumentet direkte til supersamtalen.På denne måten kan du dra nytte av de 4 forhåndsdefinerteCellestiler.
Du må også implementere
init (koder :)
, så du bør opprette en vanlig initialiseringsfunksjon der du kan legge til de tilpassede visningene dine til visningshierarkiet, som vi gjorde i LoadView -metoden ovenfor.Hvis du bruker XIB -filer og IB, kan du bruke AwakeFromNIB -metoden for å legge til ekstra stil til dine visninger gjennom standarden@IBoutlet
Egenskaper (eller legg til ekstra visninger til hierarkiet også).👍
Den siste metoden som vi må snakke om erForberedelse av
.Som jeg nevnte før celler blir gjenbrukt, så hvis du vil tilbakestille noen egenskaper, som bakgrunnen til en celle, kan du gjøre det her.Denne metoden vil bli kalt før cellen skal brukes på nytt.
La oss lage to nye celle -underklasser å leke med.
klasseDetaljcell:UITableViewCell{Overstyr init(stil:UITableViewCell.Cellstyle, gjenbruk:Streng?) {super.i det(stil: .Undertittel, gjenbruk: gjenbruk)selv-.Initialiser()}påkrevd init? (Koder Adecoder:Nscoder) {super.i det(Koder: Adecoder)selv-.Initialiser()}funcinitialiser () {// ingenting å gjøre her :)}Overstyr Funcpreparreuse () {super.Forberedelse av()selv-.Tekstlabel?.tekst=Null selv.DetaljTextLabel?.tekst=Null selv.ImageView?.bilde=nil}}
Vår tilpassede celle vil ha en stor bildebakgrunn pluss en titteletikett i midten av visningen med en tilpasset størrelse systemfont.Også jeg har lagt tilSwift LogoSom en eiendel til prosjektet, så kan vi ha et fint demobilde.🖼
klasseCustomCell:UITableViewCell{svak varCoverView:UIIMAGEVIEW!svak varTitlelabel:Uilabel!Overstyr init(stil:UITableViewCell.Cellstyle, gjenbruk:Streng?) {super.i det(Stil: Stil, gjenbrukidentifikator: gjenbrukidentifikator)selv-.Initialiser()}påkrevd init? (Koder Adecoder:Nscoder) {super.i det(Koder: Adecoder)selv-.Initialiser()}funcinitialiser () {laCoverView =UIIMAGEVIEW(ramme :.null) CoverView.OversattesautorisizingmaskIntoconstraints=Falske selv.ContentView.ADDSUBVIEW(CoverView)selv-.CoverView= CoverViewlatitlelabel =Uilabel(ramme :.null) Titlelabel.OversattesautorisizingmaskIntoconstraints=Falske selv.ContentView.ADDSUBVIEW(titlelabel)selv-.Titlelabel= titlelabelNslayoutconstraint.aktivere([selv-.ContentView.Topanchor.begrensning(Lik:selv-.CoverView.Topanchor),selv-.ContentView.Bottomanchor.begrensning(Lik:selv-.CoverView.Bottomanchor),selv-.ContentView.LEADINGANCHOR.begrensning(Lik:selv-.CoverView.LEADINGANCHOR),selv-.ContentView.Trailinganchor.begrensning(Lik:selv-.CoverView.Trailinganchor),selv-.ContentView.Centerxanchor.begrensning(Lik:selv-.Titlelabel.Centerxanchor),selv-.ContentView.senter.begrensning(Lik:selv-.Titlelabel.senter),])selv-.Titlelabel.Font=Uifont.Systemfont(OfSize:64)}Overstyr Funcpreparreuse () {super.Forberedelse av()selv-.CoverView.bilde=nil}}
Det er det, la oss begynne å bruke disse nye cellene.Jeg vil til og med fortelle deg hvordan du kan sette tilpasset høyde for en gitt celle, og hvordan du håndterer cellevalg riktig, men først må vi bli kjent med en annen delegatprotokoll.🤝
Grunnleggende UITableViewDelegate Tutorial
Denne delegaten er ansvarlig for mange ting, men foreløpig skal vi dekke bare noen få interessante aspekter, som hvordan du håndterer cellevalg og gir en tilpasset cellehøyde for hvert elementer inne i tabellen.Her er en rask prøvekode.
klasseViewController:UIViewController{Overstyr FuncviewDidLoad () {super.ViewDidload()selv-.TableView.registrere(UITableViewCell.selv-, ForcellReuseIdentifier:"UITableViewcell")selv-.TableView.registrere(Detaljcell.selv-, ForcellReuseIdentifier:"Detaljcell")selv-.TableView.registrere(CustomCell.selv-, ForcellReuseIdentifier:"CustomCell")selv-.TableView.datakilde=Selv selv.TableView.delegat=selv-}}Utvidelse ViewController:UITableViewDataSource{funcTableView (_TableView:UITableView, Cellforrowat IndexPath:IndexPath) ->UITableViewCell{laCell = TableView.DequeueReusableCell(med identifisering:"CustomCell", for: IndexPath)som!CustomCell lavare =selv-.gjenstander[IndexPath.punkt] celle.Titlelabel.tekst= elementcelle.CoverView.bilde=UIIMAGE(navngitt:"Fort")komme tilbakecelle}}Utvidelse ViewController:AschiekviewLegelate{funcTableView (_TableView:UITableView, HeightForrowat IndexPath:IndexPath) ->Cgfloat{komme tilbake 128}funcTableView (_TableView:UITableView, didselectrowat indexPath:IndexPath) {TableView.Avkeleser(AT: IndexPath, animert:ekte)lavare =selv-.gjenstander[IndexPath.punkt]laAlertController =UialertController(Tittel: Vare, melding:"Er i da House!", PreferredStyle :.varsling)laHandling =UialertAction(tittel:"OK", stil: .misligholde) {_ i} AlertController.Addaction(handling)selv-.tilstede(AlertController, animert:ekte, fullføring:nil)}}
Som du ser registrerer jeg mine splitter nye tilpassede celleklasser iViewDidload
metode.Jeg endret også koden inne iCellforrowat
IndexPath -metode, slik at vi kan brukeCustomCell
klasse i stedet forUITableViewCells
.Ikke vær redd for kraftstøping her, hvis noe går galt på dette tidspunktet, skal appen din krasje.🙃
Det er to delegatmetoder som vi bruker her.I den første må vi returnere et tall, og systemet vil bruke den høyden for cellene.Hvis du vil bruke forskjellig cellehøyde per rad, kan du også oppnå det ved å sjekke IndexPath -egenskapen eller noe sånt.Den andre er behandleren for utvalget.Hvis noen tapper på en celle, vil denne metoden bli kalt, og du kan utføre litt handling.
En indekspath har to interessante egenskaper: seksjon og element (= rad)
Flere seksjoner med overskrifter og bunntekst
Det er mulig å haFlereSeksjoner inne i tabellvisningen, vil jeg ikke gå for mye inn i detaljene, fordi det er ganske greit.Du må bare bruke indeksstier for å få / sette / returnere riktige data for hver seksjon og celle.
importUikitklasseViewController:UIViewController{svak varTableView:UITableView!varPlasserview =Uiview(ramme :.null)variSpullingdown =falsk enumStil {sak`Standard` case undertittelsaktilpasset }varstil =Stil.misligholde varElementer: [Streng[Streng]] = ["Originaler"["👽","🐱","🐔","🐶","🦊","🐵","🐼","🐷","💩","🐰","🤖","🦄"],"iOS 11.3"["🐻","🐲","🦁","💀"],"iOS 12"["🐨","🐯","👻","🦖"],]Overstyr FuncLoadView () {super.LoadView()laTableView =UITableView(ramme :.null, stil: .vanlig) TableView.OversattesautorisizingmaskIntoconstraints=Falske selv.utsikt.ADDSUBVIEW(TableView)Nslayoutconstraint.aktivere([selv-.utsikt.SafeareAlayOutguide.Topanchor.begrensning(Equalto: TableView.Topanchor),selv-.utsikt.SafeareAlayOutguide.Bottomanchor.begrensning(Equalto: TableView.Bottomanchor),selv-.utsikt.LEADINGANCHOR.begrensning(Equalto: TableView.LEADINGANCHOR),selv-.utsikt.Trailinganchor.begrensning(Equalto: TableView.Trailinganchor),])selv-.TableView= TableView}Overstyr FuncviewDidLoad () {super.ViewDidload()selv-.TableView.registrere(UITableViewCell.selv-, ForcellReuseIdentifier:"UITableViewcell")selv-.TableView.registrere(Detaljcell.selv-, ForcellReuseIdentifier:"Detaljcell")selv-.TableView.registrere(CustomCell.selv-, ForcellReuseIdentifier:"CustomCell")selv-.TableView.datakilde=Selv selv.TableView.delegat=Selv selv.TableView.separatorstyle=.enkel linje selv-.TableView.SeparatorColor=.lysegrå selv-.TableView.separatorinSet=.null selv-.NavigationItem.RightBarbuttonItem=.i det(BarbuttonSystemItem :.forfriske, mål:selv-, handling:#Selektor(selv-.ToggleCells))}@objc -funksjonToggleCells () {Bytt selv.stil{sak.misligholde:selv-.stil=.Undertittel sak.Undertittel:selv-.stil=.tilpasset sak.tilpasset:selv-.stil=.misligholde}Dispatchqueue.hoved-.async{selv-.TableView.Reloddata()}}// Mark: - Hjelpere funcNøkkel (for seksjon:Int) ->Streng{lanøkler =Array(selv-.gjenstander.nøkler).sortert{Først, sist ->Bool i hvisFørst =="Originaler"{Returner sann}komme tilbakeFørst lanøkkel = nøkler [seksjon]komme tilbakenøkkel}funcElementer (i seksjon:Int) -> [Streng] {lanøkkel =selv-.nøkkel(for: seksjon)Returnerer selv.gjenstander[nøkkel]!}funcElement (på IndexPath:IndexPath) ->Streng{laelementer =selv-.gjenstander(I: IndexPath.seksjon)komme tilbakeElementer [IndexPath.punkt]}}Utvidelse ViewController:UITableViewDataSource{funcNumberOfSections (i TableView:UITableView) ->Int{Returnerer selv.gjenstander.nøkler.telle}funcTableView (_TableView:UITableView, NumberOfRowSSection Section:Int) ->Int{Returnerer selv.gjenstander(I: Seksjon).telle}funcTableView (_TableView:UITableView, Cellforrowat IndexPath:IndexPath) ->UITableViewCell{lavare =selv-.punkt(AT: IndexPath)laCell = TableView.DequeueReusableCell(med identifisering:"CustomCell", for: IndexPath)som!CustomCellcelle.Titlelabel.tekst= elementcelle.CoverView.bilde=UIIMAGE(navngitt:"Fort")komme tilbakecelle}funcTableView (_TableView:UITableView, tittelforheaderinsection seksjon:Int) ->Streng?{Returnerer selv.nøkkel(for: seksjon)}}Utvidelse ViewController:AschiekviewLegelate{funcTableView (_TableView:UITableView, HeightForrowat IndexPath:IndexPath) ->Cgfloat{komme tilbake 128}funcTableView (_TableView:UITableView, didselectrowat indexPath:IndexPath) {TableView.Avkeleser(AT: IndexPath, animert:ekte)lavare =selv-.punkt(AT: IndexPath)laAlertController =UialertController(Tittel: Vare, melding:"Er i da House!", PreferredStyle :.varsling)laHandling =UialertAction(tittel:"OK", stil: .misligholde) {_ i} AlertController.Addaction(handling)selv-.tilstede(AlertController, animert:ekte, fullføring:nil)}}
Selv om det er et interessant tillegg i kodebiten ovenfor.Du kan ha en tilpasset tittel for hver seksjon, du må bare legge tiltitleforheaderinseksjon
datakildemetode.Jepp, det ser ut som dritt, men denne handler ikke om perfekt brukergrensesnitt.😂
Men hvis du ikke er fornøyd med utformingen av seksjonstitlene, kan du opprette en tilpasset klasse og bruke den i stedet for de innebygde.Slik gjør du en tilpasset seksjonsoverskrift.Her er implementeringen av den gjenbrukbare visningen:
klasseOmovervisning:UITABLEVIEWHEADERFOOTERVIEW{svak varTitlelabel:Uilabel!Overstyr init(Gjenbruk:Streng?) {super.i det(gjenbruk: gjenbruk)selv-.Initialiser()}påkrevd init? (Koder Adecoder:Nscoder) {super.i det(Koder: Adecoder)selv-.Initialiser()}funcinitialiser () {latitlelabel =Uilabel(ramme :.null) Titlelabel.OversattesautorisizingmaskIntoconstraints=Falske selv.ContentView.ADDSUBVIEW(titlelabel)selv-.Titlelabel= titlelabelNslayoutconstraint.aktivere([selv-.ContentView.Centerxanchor.begrensning(Lik:selv-.Titlelabel.Centerxanchor),selv-.ContentView.senter.begrensning(Lik:selv-.Titlelabel.senter),])selv-.ContentView.bakgrunnsfarge=.svart selv-.Titlelabel.Font=Uifont.BoldSystemFont(OfSize:16)selv-.Titlelabel.tekstegenskap=.senter selv-.Titlelabel.textColor=.hvit}}
Det er bare noen få ting igjen å gjøre, du må registrere overskriften, akkurat som du gjorde det for cellene.Det er nøyaktig på samme måte, bortsett fra at det er en egen registrering av "Pool" for overskriften og bunnteksten.Til slu*tt må du implementere ytterligere to, men relativt enkle (og kjente) delegatmetoder.
// Dette går til ViewDidload, men jeg vil ikke legge inn så mye kode ... :) // self.tableView.register (header view.self, ForheaderFooTeSview gjenbrukidentifikator: "Overskrift")Utvidelse ViewController:AschiekviewLegelate{/ * ... */ funcTableView (_TableView:UITableView, HeightForHeaderInseksjonsseksjon:Int) ->Cgfloat{komme tilbake 32}funcTableView (_TableView:UITableView, ViewForHeaderInseksjonsseksjon:Int) ->Uiview?{laVis = TableView.DequeueReusableHeaderFooterview(med identifisering:"Overskrift")som!Overføringutsikt.Titlelabel.tekst=selv-.nøkkel(for: seksjon)komme tilbakeVis}}
Footers fungerer nøyaktig det samme som overskrifter, du må bare implementere de tilsvarende datakildene og delegatmetodene for å støtte dem.
Du kan til og med ha flere celler i samme tabellvisning basert på rad- eller seksjonsindeksen eller et hvilket som helst spesifikt forretningskrav.Jeg skal ikke demo dette her, fordi jeg har en bedre løsning for å blande og gjenbruke celler inne iCorekit Framework.Den er allerede der for tabellvisninger også, pluss at jeg allerede dekket denne ideen i minUltimate Collection View Tutorialpost.Du bør sjekke det også.🤓
Seksjonstitler og indekser
OK, hvis hjernen din ikke er smeltet ennå, vil jeg vise deg to små ting som kan være interessante for nybegynnere.Den første er basert på to ekstra datakildemetoder, og det er et veldig hyggelig tillegg for lange lister.(Jeg foretrekker søkefelt!) 🤯
Utvidelse ViewController:UITableViewDataSource{/ * ... */ funcAVSNITTINGSEPSTITLER (for TableView:UITableView) -> [Streng]?{komme tilbake["1","2","3"]}funcTableView (_TableView:UITableView, SeksjonsForsctionIndextitle Tittel:Streng, ved indeks:Int) ->Int{komme tilbakeindeks}}
Hvis du skal implementere disse metodene ovenfor, kan du ha et lite indekssyn for seksjonene dine på høyre side av tabellvisningen, slik at slu*ttbrukeren kan raskt hoppe mellom seksjonene.Akkurat som i den offisielle kontakten -appen.📕
Valg mot høydepunkt
Celler blir fremhevet når du holder dem nede med fingeren.Cell kommer til å bli valgt hvis du slipper fingeren fra cellen.
Ikkeover-komplisererdette.Du må bare implementere to metoder i din tilpassede celleklasse for å få alt til å fungere.Jeg foretrekker å fjerne markeringen av cellene mine med en gang, hvis de ikke for eksempel brukes av en slags dataplukkeroppsett.Her er koden:
klasseCustomCell:UITableViewCell{/ * ... */ Overstyr FuncsetSelert (_valgt:Bool, animert:Bool) {selv-.CoverView.bakgrunnsfarge= valgt?.rød:.klar}Overstyr FuncSethighlighted (_fremhevet:Bool, animert:Bool) {selv-.CoverView.bakgrunnsfarge= uthevet?.blå:.klar}}
Som du kan se, er det latterlig enkelt, men de fleste nybegynnere vet ikke hvordan de skal gjøre dette.De glemmer også å tilbakestille celler før gjenbrukslogikken skjer, så listen fortsetter å rote celletilstander.Ikke bekymre deg for mye om disse problemene, de vil forsvinne når du kommer til å bli mer erfaren med UITableView API -ene.