Pääsivulle | TIETOTEKNIIKAN PÄÄSIVULLE
Sovelluksen käyttöliittymän logiikan
perusratkaisu
Seuraavassa on kerrottu Herbaario- ja Kuva-albumisovellusteni
toteutuksen luuranko. Se on samanlainen molemmissa sovelluksissa.
Sovellukset toimivat pääpiirteissään näin: On päämenu, josta
valitaan toiminto, esimerkiksi Kasvien haku. Annetaan hakuehdot ja
saadaan hakutulokset. Valitaan joku sieltä ja klikkaus Näytä tiedot.
Avautuu uusi näkymä, josta voi jatkaa seuraaviin (kuten tietojen
muokkaus, kuvan esittäminen).
Erilaisia näkymiä on 15-20 ja niistä pitää päästä toisiinsa.
Käyttämäni peruslogiikka on yksinkertainen, tehokas ja helposti
laajennettavissa.
Sen keskeiset elementit ovat:
- yksinkertainen muuttujarakenne
- seurx-taulukko, joka ylläpitää työprosessissa olevien
kokonäkymien datan
- tila-muuttuja, jossa on yksittäisen näkymän data; sen
avulla voidaan näkymä piirtää samanlaisena uudestaan
- ContentView:n case-lista navigointiin
- Päänäkymä, jossa valitaan mitä tehdään (view Paamenut)
- Työnäkymät, joista edetään seuraavaan tai palataan
aiempaan näkymään
- joitain näkymiä esitetään sheetteinä (.sheet)
Yksinkertainen muuttujarakenne tarkoittaa seuraavaa:
- käytössä ei ole @EnvironmentObject
- käytössä ei ole @ObservableObject - @ObservedObject eikä
@Published
- käytössä on globaaleja muuttujia ja funktioita
- käytössä ovat @State - @Binding
- apuna tarvittavat ryhmäobjektit ovat tyypiltään toinen näistä:
- struct Ruksi: Identifiable { var id = UUID() ;
var zz = ""; ... }
- class Albu: NSObject { var nimiz = ""; ... }
Tila-muuttuja on määritelty näin. Siinä on eri muuttujia
kuvaamaan näkymän tilaa:
struct Tila:
Identifiable
{
var id = UUID()
var seurx: Int //
seuraava näkymä, esim KASVIHAKU, KUVAKATSO
var idkuva = EIOO // input
Kuvatieto ja Kuvamuok
var idrivi = EIOO // valittu rivi
(Vakmonta <-> kartat)
var idmuisti = EIOO // idKuva jota
halutaan kopioida Kuvatieto -> Kuvamuok
var kartyy = "" //
karttatyyppi AppleMap / maasto
//.....
init(seur: Int) { seurx = seur }
}
seurx-muuttuja määritellään ContentView:ssä:
@State var
seurx = [Tila(seur: PAAMENU)] // lähtöarvona on meno
näkymään "Päämenu"
Tilamuuttujan arvoina ovat myös:
var
activesheet: ActiveSheet? = nil // Näkymä tietää
olevansa sheetissä ja osaa sulkea sen
var alertItem: AlertItem? = nil //
Alertti esiin
ContentView:n muuttajina (modifier) ovat .sheet ja .alert ja
tilamuuttujan välityksellä saan avautumaan tarpeen mukaan alertin
tai sheetin ja sen sulkemisen jälkeen niitä kutsunut näkymä on
edelleen esillä.
Muuttuja Tila.seurx tietää mihin mennään ja mihin palataan.
Se määritellään Tila-muuttujan osana (ks edellä).
PAAMENU ja vastaavat ovat nyt sovelluksen globaaleja vakioita, mutta
voisi tässä käyttää merkkijonojakin kuten "PAAMENU".
Muuttujaa seurx käytetään näin vaihdettaessa päänäkymää, katso
tarkemmin jäljempänä:
// siirtyminen seuraavaan näkymään:
var tila = Tila(seur: KARTTA) // menossa
karttaselaimeen
tila.ehtomz = "Maastokartta" // annetaan
inputtia näkymälle
tila.latiz = seurx[0].latiz
tila.longiz = seurx[0].longiz
tila.kinfoz = seurx[0].kinfoz
seurx.insert(tila, at: 0) //
näkymä avataan tämän jälkeen ContentView:ssä
// siirtyminen
edelliseen näkymään:
seurx.removeFirst()
ContentView sisältää case-listan siitä mikä näkymä nyt
avataan. Näkymät ovat koko ikkunan peittäviä päänäkymiä, joiden
osana voi toki olla osanäkymiä. Seuraavan päänäkymän valinta riippuu
siitä, mikä on taulukon seurx[] ensimmäinen arvo. Näkymien kutsuissa
välitetään eteenpäin seurx:
var body:
some View
{
VStack
{
switch seurx[0].seurx
{
case PAAMENU:
Paamenut(seurx: $seurx)
case KARTTA:
Karttaselain(seurx: $seurx)
.....
Omissa sovelluksissani on 15-20 eri näkymää, joiden välillä
kuljetaan.
Käytännössä ContentView:ssä on ylläpidettävä muitakin muuttujia,
joita useat näkymät tarvitsevat. Ne voi leipoa Tila-muuttujan sisään
tai pitää erillisinä. Minulla tällaisia ovat mm. kuvien hakunäytön
kentät ja kuvahaun tulostaulukko.
Paamenut on view, jossa on perustason valikko minne mennään:
var body:
some View
{
VStack(spacing: 0)
{
HStack
{
Menu("TILASTOT")
{
Button("Henkilöt", action:
{
var tila = Tila(seur: HENKILOLKM)
tila.vaklaji = LISTA // annetaan jotain inputtia
seurx.insert(tila, at: 0)
})
Button("Vuodet", action:
{
seurx.insert(Tila(seur: VUOSI, at: 0))
})
// ...
} } } }
Tässä testisovellukseni Paamenut -näkymän vasen ylänurkka. Halutut
toiminnat voidaan valita alasvetovalikoista tai buttoneista:

Työnäkymissä tehdään varsinaisia hommia, kuten kuvien hakua,
katselua ja niiden metatietojen muokkaamista.
Eri näkymissä määritellään seurx-muuttuja:
@Binding var seurx: [Tila]
Työnäkymästä voidaan siirtyä seuraavaan näkymään esimerkiksi
Buttonin toimintona näin:
// siirtyminen seuraavaan näkymään:
var tila = Tila(seur: KARTTA) // menossa
karttaselaimeen
tila.ehtomz = "Maastokartta" // annetaan
inputtia näkymälle
tila.latiz = seurx[0].latiz
tila.longiz = seurx[0].longiz
tila.kinfoz = seurx[0].kinfoz
seurx.insert(tila, at: 0) //
näkymä avataan tämän jälkeen ContentView:ssä
Siirtyminen tapahtuu välittömästi ja esillä oleva näkymä
korvautuu uudella.
Palaaminen edelliseen näkymään tapahtuu näin:
seurx.removeFirst() // siirtyminen edelliseen näkymään
Tällöin logiikka siirtyy ContentView:n riville switch seurx[0].seurx koska
kyseinen arvo muuttui. Nykyinen näkymä poistuu ja tilalle tulee
haluttu näkymä. Halutun näkymän kaikki tiedot lasketaan uudestaan,
tai otetaan @Binding-muuttujista
Tässä esimerkki eräästä näkymästä. Buttoneista valitaan seuraavia
toimia, ja tilalle avautuu toinen näkymä (buttonit Poistu, Kohteen
tiedot, Näytä iso kuva)

-----------------------
(sivua muokattu 15.1.2022)