Nummi (Lohja) Pitkäjärven uimaranta

  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:
Sovelluksen päämenu


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)

Hakunäytön yläosa






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