Kehittäminen useille näytön kokoille ja suuntauksille räpylässä (fragmentit räpylässä)

Mukauttavien näyttöjen tekeminen Googlen Flutter Mobile SDK: ssa

Mobiilisovellusten on tuettava laajaa valikoimaa laitekokoja, pikselitiheyksiä ja suuntauksia. Sovellusten on kyettävä skaalaamaan hyvin, käsittelemään suunnanmuutoksia ja säilyttämään tietoja kaikkien näiden kautta. Flutter antaa sinulle kyvyn valita tapa vastata näihin haasteisiin sen sijaan, että annettaisiin vain yksi tietty ratkaisu.

Android-ratkaisu suurempien näyttöjen käsittelemiseen

Androidissa käsittelemme suurempia näyttöjä, kuten tablet-laitteita, vaihtoehtoisilla asetustiedostoilla, jotka voidaan määrittää vähimmäisleveydelle ja vaaka- / pystysuunnalle.

Tämä tarkoittaa, että meidän on määritettävä yksi asetustiedosto puhelimille, yksi tablet-laitteille ja sitten molemmat suuntaukset jokaiselle laitetyypille. Nämä asettelut välitetään sitten sen mukaan, kumpi laite sitä käyttää. Tarkistamme sitten, mikä asettelu on aktiivinen (matkapuhelin / tabletti), ja alustaa sen mukaan.

Suurimmassa osassa sovelluksia isompien yksityiskohtien virtausta käytetään suurempien näyttökokojen käsittelemiseen, joka käyttää Fragmentteja. Tarkastellaan sitä, mikä isäntä- ja yksityiskohtavirta on hetkessä.

Fragmentit Androidissa ovat pääosin uudelleenkäytettäviä komponentteja, joita voidaan käyttää näytössä. Fragmentteillä on omat asettelut ja Java / Kotlin-luokat datan hallitsemiseksi ja fragmentin elinkaaren ajaksi. Tämä on melko suuri yritys ja vaatii paljon koodia työskennelläkseen.

Katsotaanpa ensin käsittelyn suuntausta ja sitten käsittelemään Flutter-näytön kokoja.

Työskentely suuntautumisen kanssa Flutterissa

Kun työskentelemme suunnistuksen kanssa, haluamme käyttää koko näytön leveyttä ja näyttää mahdollisimman suuren määrän tietoja.

Seuraava esimerkki luo alkeellisen profiilisivun molemmissa suunnissa ja rakentaa asettelun eri tavalla suunnasta riippuen, jotta ruudun leveys voidaan maksimoida. Koko lähdekoodi isännöidään GitHubissa (linkki annettu tämän artikkelin lopussa).

Täällä meillä on yksinkertainen näyttö, jolla on erilaiset asettelut sekä pystysuunnassa että maisemassa. Yritetään ymmärtää, kuinka todella vaihdamme asetteluja Flutterissa luomalla yllä oleva esimerkki.

Kuinka jatkamme tätä?

Periaatteessa toimimme hyvin samalla tavalla kuin Android-tapa toimia. Meillä on kaksi asettelua (ei asetustiedostoja, koska Flutterilla ei ole niitä), yksi pystysuuntainen ja toinen vaakasuuntainen. Kun laite muuttaa suuntaa, rakennamme uudelleen ulkoasun.

Kuinka havaitsemme suunnan muutokset?

Aloittamiseksi käytämme OrientationBuilder-nimistä widgettiä. OrientationBuilder on widget, joka rakentaa asettelun tai sen osan orientaatiomuutokselle.

@ohittaa
Widget-rakennus (BuildContext-konteksti) {
  palauta rakennustelineet (
    appBar: AppBar (),
    runko: OrientationBuilder (
      rakentaja: (konteksti, suunta) {
        paluusuunta == Suunta.suunta
            ? _buildVerticalLayout ()
            : _buildHorizontalLayout ();
      },
    ),
  );
}

OrientationBuilderillä on rakennustoiminto rakentaa asettelumme. Rakennustoiminto kutsutaan, kun suunta muuttuu. Mahdollisia arvoja ovat Orientation.portrait tai Orientation.landscape.

Tässä esimerkissä tarkistamme, onko näyttö pystysuunnassa, ja rakennamme tällöin pystysuuntaisen asettelun. Muussa tapauksessa rakennamme näytön vaakasuuntaisen asettelun.

_buildVerticalLayout () ja _buildHorizontalLayout () ovat menetelmiä, jotka olen kirjoittanut vastaavien asettelujen luomiseksi.

Voimme tarkistaa myös suunnan missä tahansa koodin kohdassa (OrientationBuilderin sisällä tai ulkopuolella) käyttämällä

MediaQuery.of (yhteydessä) .orientation

Huomaa: Siihen aikaan, kun olemme laiskoja ja / tai vain muotokuva tekee, käytä

SystemChrome.setPreferredOrientations (DeviceOrientation.portraitUp);

Asettelujen luominen suuremmille näytöille Flutterissa

Kun käsittelemme suurempia näyttökokoja, haluamme, että näytöt mukautuvat käyttämään näytön vapaata tilaa. Yksinkertaisin tapa tehdä tämä on yksinkertaisesti luoda kaksi erilaista asettelua tai jopa näyttöä tablet-laitteille ja puhelimille. (Tässä ”asettelu” tarkoittaa näytön visuaalista osaa. ”Näyttö” tarkoittaa asettelua ja kaikkia siihen liitettyjä taustakoodeja.) Tähän sisältyy kuitenkin paljon turhaa koodia ja koodi on toistettava.

Joten mitä teemme tämän ongelman ratkaisemiseksi?

Katsotaanpa ensin sen yleisintä käyttötapaa.

Palataan takaisin "Master-Detail Flow" -tapahtumaan, josta aiomme puhua. Sovellusten kohdalla näet yleisen kuvion, jossa sinulla on pääluettelo kohteista ja kun napsautat luettelon kohtaa, sinut ohjataan toiseen yksityiskohtaruutuun. Otetaan esimerkki Gmailista, jossa meillä on luettelo sähköposteista ja kun napsautamme yhtä, yksityiskohtanäkymä avautuu postin sisällön kanssa.

Tehdään esimerkki sovelluksesta tälle virtaukselle.

Master-Detail Flow liikkuvassa muototilassa

Tämä sovellus pitää yksinkertaisesti luettelonumeroista ja näyttää numeron näkyvästi, kun sitä kosketetaan. Meillä on pääluettelo numeroista ja yksityiskohtakuva, joka näyttää numeron napsautettaessa. Aivan kuten sähköpostit.

Jos käyttäisimme samaa asettelua tableteissa, se olisi melko suurta tilaa. Joten mitä voimme tehdä sen ratkaisemiseksi? Meillä voi olla sekä pääluettelo että yksityiskohtaiset näkymät samassa näytössä, koska meillä on käytettävissä näyttötilaa.

Master-Detail Flow tablet-laitteen vaakatilassa

Joten mitä voimme tehdä vähentääksemme kahden erillisen näytön kirjoittamista?

Katsotaanpa kuinka Android käsittelee tätä. Android luo uudelleenkäytettäviä osia, nimeltään Fragments, pääluettelosta ja yksityiskohtaisesta näkymästä. Fragmentti voidaan määritellä erikseen näytöstä ja lisätä vain näytölle toistamatta koodia kahdesti.

Joten fragmentti A on pääluettelon fragmentti ja B on yksityiskohta fragmentti. Matkapuhelimissa tai pienemmissä leveysasetteluissa luettelon kohteen napsauttaminen siirtyisi erilliselle sivulle, kun taas tableteissa se pysyisi samalla sivulla ja muuttaisi yksityiskohtien fragmenttia. Voimme tehdä myös tablet-tyyppisen käyttöliittymän, kun puhelinta käännetään vaaka-asentoon.

Tähän kohtaan tulee Flutterin voima.

Jokainen Flutter-widget on luonteeltaan uudelleen käytettävä.

Jokainen Flutter-widget on kuin katkelma.

Meidän tarvitsee vain määritellä kaksi widgettiä. Yksi pääluettelolle, toinen yksityiskohtaiselle näkymälle. Nämä ovat käytännössä katkelmia. Me vain tarkistamme, onko laitteella tarpeeksi leveyttä käsitellä sekä luettelo- että yksityiskohtaosaa. Jos näin käy, käytämme molempia widgettejä. Jos laitteella ei ole tarpeeksi leveyttä molempien tukemiseksi, näytämme vain luettelon ja siirrymme erilliseen näyttöön yksityiskohtien sisällön näyttämiseksi.

Ensin on tarkistettava laitteen leveys nähdäksemme, voimmeko käyttää suurempaa asettelua pienemmän sijasta. Leveyden saamiseksi käytämme

MediaQuery.of (yhteydessä) .size.width

Koko antaa meille laitteen korkeuden ja leveyden dps: nä.

Asetetaan vähimmäisleveys arvoon 600 dp, kun haluat siirtyä toiseen asetteluun.

Yhteenvetona:

  1. Luomme kaksi widgettiä, joista toinen sisältää pääluettelon ja toinen yksityiskohtanäkymän.
  2. Luomme kaksi näyttöä. Ensimmäisessä näytössä tarkistamme, onko laitteen riittävä leveys käsitellä molempia widgettejä.
  3. Jos leveyttä on riittävästi, lisäämme molemmat widgetit yhdelle sivulle. Jos sitä ei ole, siirrymme toiselle sivulle, kun napautetaan luettelon kohdetta, josta on vain yksityiskohtainen näkymä.

Koodataan se

Koodataan demo, jonka olen sisällyttänyt tämän osan yläosaan, jossa meillä on luettelo numeroista ja yksityiskohtaiset näkymät tuovat numeron näkyviin. Ensin teemme kaksi widgettiä.

Lista-widget (luettelon fragmentti)

typedef Null ItemSelectedCallback (int-arvo);

luokan ListWidget laajentaa StatefulWidget {
  lopullinen int määrä;
  lopullinen ItemSelectedCallback onItemSelected;

  ListWidget (
    this.count,
    this.onItemSelected,
  );

  @ohittaa
  _ListWidgetState createState () => _ListWidgetState ();
}

luokka _ListWidgetState laajentaa tilaa  {
  @ohittaa
  Widget-rakennus (BuildContext-konteksti) {
    return ListView.builder (
      itemCount: widget.count,
      itemBuilder: (konteksti, sijainti) {
        palautuspehmuste (
          pehmuste: const EdgeInsets.all (8.0),
          lapsi: kortti (
            lapsi: InkWell (
              hanassa: () {
                widget.onItemSelected (asento);
              },
              lapsi: Rivi (
                lapset:  [
                  pehmusteena (
                    täyte: const EdgeInsets.all (16.0),
                    lapsi: Teksti (position.toString (), tyyli: TextStyle (fontSize: 22.0),),
                  ),
                ],
              ),
            ),
          ),
        );
      },
    );
  }
}

Luettelossa otamme, kuinka monta kohdetta haluamme näyttää, sekä soittopyynnön, kun jotain napsautetaan. Tämä takaisinsoitto on tärkeä, koska se päättää, vaihdetaanko vain yksityiskohtaisempi näkymä suuremmalla näytöllä vai navigoidaanko toiselle sivulle pienemmällä näytöllä.

Näytämme kortit jokaisesta hakemistosta ja ympäröimme sitä InkWell-laitteella vastatakseen napoihin.

Yksityiskohtainen widget (yksityiskohtaisuus)

luokan DetailWidget laajentaa StatefulWidget {

  lopullinen int-data;

  DetailWidget (this.data);

  @ohittaa
  _DetailWidgetState createState () => _DetailWidgetState ();
}

luokka _DetailWidgetState laajentaa tilan  {
  @ohittaa
  Widget-rakennus (BuildContext-konteksti) {
    paluukontti (
      väri: Colors.blue,
      lapsi: Center (
        lapsi: sarake (
          mainAxisAlignment: MainAxisAlignment.center,
          lapset:  [
            Teksti (widget.data.toString (), tyyli: TextStyle (fontSize: 36.0, väri: Colors.white),),
          ],
        ),
      ),
    );
  }
}

Yksityiskohtainen widget ottaa yksinkertaisesti numeron ja näyttää sen näkyvästi.

Huomaa, että nämä eivät ole näyttöjä. Nämä ovat yksinkertaisesti widgettejä, joita aiomme käyttää näytöillä.

Päänäyttö

luokan MasterDetailPage laajentaa StatefulWidget {
  @ohittaa
  _MasterDetailPageState createState () => _MasterDetailPageState ();
}

luokka _MasterDetailPageState laajentaa tilaa  {
  var valitudValue = 0;
  var isLargeScreen = false;

  @ohittaa
  Widget-rakennus (BuildContext-konteksti) {
    palauta rakennustelineet (
      appBar: AppBar (),
      runko: OrientationBuilder (rakentaja: (konteksti, suunta) {
        
        if (MediaQuery.of (konteksti) .koko.leveys> 600) {
          isLargeScreen = tosi;
        } muuta {
          isLargeScreen = epätosi;
        }

        paluurivi (lapset:  [
          laajennettu (
            lapsi: ListWidget (10, (arvo) {
              if (isLargeScreen) {
                selectedValue = arvo;
                setState (() {});
              } muuta {
                Navigator.push (konteksti, MaterialPageRoute (
                  rakentaja: (konteksti) {
                    paluu DetailPage (arvo);
                  },
                ));
              }
            }),
          ),
          isLargeScreen? Laajennettu (alaosa: DetailWidget (selectedValue)): Container (),
        ]);
      }),
    );
  }
}

Tämä on sovelluksen pääsivu. Meillä on kaksi muuttujaa: selectedValue valitun luettelokohteen tallentamiseen, ja isLargeScreen on yksinkertainen boolean, joka tallentuu, jos näyttö on riittävän suuri, jotta se näyttää sekä luettelon että yksityiskohdat-widgetit.

Ympärillämme on myös OrientationBuilder, joten jos matkapuhelin käännetään vaakatilaan ja sillä on tarpeeksi leveyttä molempien elementtien näyttämiseksi, se rakentuu uudelleen tällä tavalla.

Tarkistamme ensin, onko leveys riittävän suuri, jotta näytämme asettelumme käyttämällä

if (MediaQuery.of (konteksti) .koko.leveys> 600) {
          isLargeScreen = tosi;
        } muuta {
          isLargeScreen = epätosi;
        }

Koodin pääosa on:

isLargeScreen? Laajennettu (alaosa: DetailWidget (selectedValue)): Container (),

Jos näyttö on suuri, lisäämme yksityiskohta-widgetin, ja jos se ei ole, palautamme tyhjän säilön. Käytämme laajennettuja widgettejä sen ympärillä täyttääksesi näytön tai jakaaksesi näytön mittasuhteisiin, jos näyttö on suurempi. Joten Laajennettu antaa jokaisen widgetin täyttää puolet näytöstä tai jopa tietyn prosenttiosuuden asettamalla Flex-ominaisuuden.

Toinen tärkeä osa on:

if (isLargeScreen) {
                selectedValue = arvo;
                setState (() {});
              } muuta {
                Navigator.push (konteksti, MaterialPageRoute (
                  rakentaja: (konteksti) {
                    paluu DetailPage (arvo);
                  },
                ));
              }

Tarkoittaa, että jos käytetään suurempaa asettelua, meidän ei tarvitse siirtyä toiselle näytölle, koska yksityiskohta-widget on sivulla. Jos näyttö on pienempi, meidän on siirryttävä toiselle sivulle, koska vain luettelo näkyy nykyisessä näytössä.

Ja lopuksi,

Yksityiskohtainen sivu (pienemmille näytöille)

luokan DetailPage laajentaa StatefulWidget {

  lopullinen int-data;

  DetailPage (this.data);

  @ohittaa
  _DetailPageState createState () => _DetailPageState ();
}

luokka _DetailPageState laajentaa tilan  {
  @ohittaa
  Widget-rakennus (BuildContext-konteksti) {
    palauta rakennustelineet (
      appBar: AppBar (),
      runko: DetailWidget (widget.data),
    );
  }
}

Sillä on vain yksi yksityiskohta-widget sivulla, ja sitä käytetään tietojen näyttämiseen pienemmillä näytöillä.

Nyt meillä on toimiva sovellus, joka mukautuu erikokoisiin näytöihin ja niiden suuntaan.

Joitakin tärkeitä asioita

  1. Jos haluat yksinkertaisesti olla erilaisia ​​asetteluita ja ilman mitään fragmenttimäisiä asetteluita, voit kirjoittaa vain rakennusmenetelmän sisällä
if (MediaQuery.of (konteksti) .koko.leveys> 600) {
          isLargeScreen = tosi;
        } muuta {
          isLargeScreen = epätosi;
        }
palaa isLargeScreen? _buildTabletLayout (): _buildMobileLayout ();

Ja kirjoita kaksi tapaa rakentaa asettelut.

2. Jos haluat suunnitella vain tablet-laitteita, sen sijaan, että tarkistaisit leveyden MediaQuerystä, hanki koko ja käytä sitä saadaksesi todellinen leveys leveyden sijasta kyseisessä suunnassa. Kun käytimme leveyttä suoraan MediaQuerystä, se saa leveyden vain siinä suunnassa. Joten vaakatilassa puhelimen pituutta pidetään leveytenä.

Koko = MediaQuery.of (konteksti) .koko;
tuplaleveys = koko.leveys> koko.korkeus? koko.korkeus: koko.leveys;

if (leveys> 600) {
  // Tee jotain tabletteja varten täällä
} muuta {
  // Tee jotain puhelimille
}

Github-linkki tämän artikkelin näytteille:

https://github.com/deven98/FlutterAdaptiveLayouts

Se on tämä artikkeli! Toivottavasti nautit siitä ja jätät muutaman taputuksen, jos teit. Seuraa minua saadaksesi lisää Flutter-artikkeleita ja kommentoidaksesi palautetta, joka sinulla voi olla tästä artikkelista.

Jotkut muista artikkeleistani

Löydä lisää sisältöä Flutter-yhteisöstä ja seuraa ilmoituksia Twitterissä.