NSCollectionView -
matriisinäkymä
Matriisinäkymässä tyypillisesti esitetään kuvia ja niiden ohella
mahdollisesti kuvan nimiä tai vastaavaa. Koodaaminen on hieman
haastavaa lähinnä sen takia, että netistä löytyy lähinnä vain
vanhentuneita ja sen takia toimimattomia ohjeita. Ja niistäkin vain
osa Swift-kielellä. Ja esimerkiksi Applen tuorein koodausesimerkki
on ikkunoiden ja ohjelmatiedostojen käsittelyssä toivottoman
monimutkainen ja hukkaa muun sälän alle NSCollectionView:n keskeisen
koodaustavan.
Seuraavassa luokka, joka sisältää NSCollectionView:n, on nimeltään
Matriisi. Sitä varten tehdään xib- ja swift-tiedostot. Lisäksi
matriisin yhtä elementtiä varten on luokka Matritem, jolle tehdään
xib- ja swift-tiedostot. Lisäksi on erillinen tiedosto
MatritemView.swift, jossa kuvataan eräät View:n poikkeukset. Ohjelmointiesimerkissä
NSCollectionView:n sisältämä luokka on nimeltään Tabikku. Esimerkki
on koodattu: Swift 4, macOS 10.13, Xcode 9.3.
Konffaus käyttöliittymäeditorissa
Tee uusi Cocoa-tiedosto Matriisi valikon kautta
(File->New->File): Cocoa class, Subclass of
NSCollectionViewItem, Also creat XIB file.
Matritem.swift ja MatritemView.swift:
- laita datarakenteet paikoilleen (tietolähde, delegaattifunktiot,
MatritemView mallin mukaan), ks. edellämainittu ohjelmointiesimerkki
- kiitokset: https://github.com/klaas/CollectionViewElCapitan
Matritem.xib:
Raahaa dokumenttisarakkeeseen Collection View Item, ja merkitse:
Identity Inspector / Class = Matritem.
Aluksi on vain Custom View. Nyt sinne lisätään paikka kuvalle ja
tekstille. Älä laita kummallekaan mittoja (width, height), se
tehdään koodissa. Mutta korjaa tekstin korkeudeksi 16. Toimenpiteet:
- From the Object Library, add an Image View to
View
- Select and click Pin from the Auto Layout
toolbar to set its constraints

Huom! Jotta Pin näkyisi,
oikean ylälaidan kohdassa "File Inspector" on oltava ruksattuna "Use
Auto Layout"
- Set the top, leading and trailing constraints to
0 (tai esim 1 mutta muuta kaikkia), the bottom to 22 and click Add 4
Constraints
- Select Editor \ Resolve Auto Layout Issues \
Update Frames (ei aina tarpeen)
- Add a Label below the Image View, and click the
Pin button.
- Set the top, bottom, trailing and leading
constraints to 0 (tai esim 1 mutta muuta kaikkia), and then click
Add 4 Constraints
- Select Editor \ Resolve Auto Layout Issues \
Update Frames (ei aina tarpeen)
Tee outletit imageview:lle (imaviewKuva) ja labelille (labelSelite),
huomaa Objectin valinta:

Tee Connections Inspector -näytössä tälle Matritem-objektille outlet
-> View ctrl-vetämällä view:n oikean reunan ympyrästä vasemmalle:

View:
- Identity Inspector: Class = MatritemView (jolle
on swift-faili)
- (muille ei lisättävää)
imaviewKuva:
- Attributes Inspector: Alignment alas
keskelle
- Bindings Inspector / Value:
- Bind to = Matritem
- Model Key Path =
representedObject.kuva (kirjoita kenttään)
- Connections Inspector: täällä pitäisi näkyä em.
Bindings ja Referencing outlet
labelSelite:
- Attributes Inspector: Alignment keskelle, Font
tarvittaessa pienemmäksi, Line Break: Truncate Tail
- Bindings Inspector / Value:
- Bind to = Matritem
- Model Key Path =
representedObject.selite (kirjoita kenttään)
- Connections Inspector: täällä pitäisi näkyä em.
Bindings ja Referencing outlet

Ylläolevalle objektille
- Identity Inspector: Class = Matritem
Connections Inspector lopuksi:

Koodaus:
Luokan nimessä määrittele TableView:tä varten tieto, että
taulukkonäkymän ja tietolähteen tuki löytyvät samasta luokasta:
class
Matriisi: NSWindowController, NSCollectionViewDataSource,
NSCollectionViewDelegate
Luokkamuuttujiksi myös taulukko, josta data otetaan (luokkien
taulukko):
var kuvat =
[Kuvainfo]()
@IBOutlet weak var colleView: NSCollectionView!
Tässä Kuvainfo on luokka, joka pitää erikseen määritellä, esimerkki
alla. Luokan muuttujista ei tarvitse kaikkia käyttää
taulukkonäkymässä, käytettävät kerrotaan koodissa:
class Kuvainfo:
NSObject
{
@objc var idKuva: Int = -1
@objc var Pvm: String = ""
@objc var Nimi: String = ""
@objc var kuva: NSImage? = nil
@objc var polkuz: String = ""
@objc init(idKuva: Int, .....)
{
//....
}
}
Luokan muodostajaan windowDidLoad() lisää rivit:
colleView.delegate = self
colleView.dataSource = self
Seuraavat taulukkonäkymän tukifunktiot tarvitaan (eka ja kolmas ovat
pakollisia):
func
collectionView(_ collectionView: NSCollectionView,
itemForRepresentedObjectAt indexPath: IndexPath) ->
NSCollectionViewItem { }
func collectionView(_ collectionView: NSCollectionView,
didSelectItemsAt indexPaths: Set<IndexPath>) { }
func collectionView(_ collectionView: NSCollectionView,
numberOfItemsInSection section: Int) -> Int
{
return kuvat.count
}
Ensimmäinen käytännössä vie sisällön taulukosta kuvat matriisinäkymään.
Toinen tulee kutsutuksi silloin kun käyttäjä valitsee matriisin
jonkun elementin.
Kolmas kertoo matriisin elementtien lukumäärän.
Näillä funktioilla taustajärjestelmät hoitavat matriisinäkymää ja
käyttäjän toimenpiteitä.
Funktioiden sisällä on omia muuttujia ja vakioita, katso
ohjelmointiesimerkki.
Sovelluksen alussa viedään taulukkoon kuvat sisältö, ja kun
aloitusfunktiot on suoritettu, myös taulukkonäkymässä ovat tiedot
paikoillaan. Tietolähteen (kuvat) tietoja voi myöhemmin muuttaa vaikkapa
vain yhden tiedon osalta (esimerkiksi päivämäärää), minkä
jälkeen seuraavalla komennolla taulukkonäkymä päivittyy ja säilyy
samalla kohdalla:
colleView.reloadData()
Taulukko ja matriisi tyhjennetään kokonaan näin:
kuvat.removeAll()
colleView.reloadData()
Mikä elementti on kuvamatriisissa valittuna:
let valitut =
colleView.selectionIndexPaths
if valitut.count > 0 // 0 = ei ole mitään valittuna
{
let indpath = valitut.first
let inde = indpath!.item
print("Valitun id=\(kuvat[inde].idKuva)")
}
Tehdään valituksi matriisin kuva, jonka idKuva = idi, esimerkki
alla. Tässä myös skrollataan valittu kuva näkyviin:
var merk =
false
for i in 0..<kuvat.count
{
if kuvat[i].idKuva == idi
{
colleView.selectItems(at:
[IndexPath(item: i, section: 0)], scrollPosition:
NSCollectionView.ScrollPosition.top)
merk = true
}
else // vanhojen valintojen poisto on
tarpeen!
{
colleView.deselectItems(at:
[IndexPath(item: i, section: 0)])
if
colleView.selectionIndexPaths.count == 1 && merk == true
{
break
}
}
}
Matriisin elementin klikkaamisella halutaan tapahtuvan jotain:
kirjoita haluamaasi koodia tähän delegaatin funktioon:
func
collectionView(_ collectionView: NSCollectionView,
didSelectItemsAt indexPaths: Set<IndexPath>) { }
--------------------------------
(sivua muokattu 7.4.2018)