Responsive Layouts: Mit Flutter von der Mobile-App zur Web-App

Seite 3: Die Stage

Inhaltsverzeichnis

Die Stage sieht auf den ersten Blick recht simpel aus: Neben- oder untereinander soll sie einen Textblock und ein Bild anzeigen, beide Elemente vor einem einheitlichen hellgrauen Hintergrund. Auch hier sollen die Inhaltselemente wieder zentriert mit einer Maximalbreite und Abstand nach links und rechts angeordnet werden, um das Basis-Layout der Navigation konsistent weiterzuführen.

Daraus ergeben sich folgende kleine Challenges:

  • Aufgrund der Leserichtung ändert sich die Reihenfolge der Elemente: In der mobilen Ansicht erscheint erst das Bild und dann der Text, auf dem Desktop verhält es sich umgekehrt.
  • Der graue Hintergrund läuft über die volle Viewport-Breite.
  • Flutter-Erfahrene wissen, dass Text-Widgets ein gewöhnungsbedürftiges Umbruchverhalten haben und der ein oder andere Trick nötig ist.

Bei der Abbildung der Reihenfolge hilft die Unterscheidung zwischen Mobile- und Desktop-Widgets. So lassen sich die Children jeweils in der richtigen Abfolge in DesktopStage und MobileStage platzieren. Wichtig ist hierbei, dass bei Mobile eine Column benutzt wird, da die Widgets untereinander erscheinen sollen. Auf dem Desktop sorgt hingegen eine Row für die Darstellung der Widgets nebeneinander.

Für die Realisierung des grauen Hintergrundes über die volle Viewport-Breite kommt ein klassisches Bootstrap-Container-Verhalten zum Einsatz. Bei Bootstrap haben Container immer eine gewisse Maximalbreite – je nach Größe des Viewports – und werden horizontal zentriert. Die entsprechende Verschachtelung von Elementen ermöglicht, dass die Elemente in Containern links und rechts gleich ausgerichtet sind und eine gemeinsame Flucht entsteht. Die Eltern der Container behalten hingegen grundsätzlich die volle Viewport-Breite und lassen sich dann entsprechend mit einer Hintergrundfarbe oder einem Hintergrundbild belegen.

In diesem Beispiel läuft ein Container-Widget mit der grauen Hintergrundfarbe über die volle Breite. In ihm wird ein Center-Widget platziert, welches wiederum einen Container als Child erhält. Der constraints-Parameter begrenzt den Container auf eine maximale Breite von 600 Pixeln bei Mobile und 1200 Pixeln auf dem Desktop. Der Container erhält eine Row mit den Stage-Komponenten.

class MobileStage extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
   return Container(
     color: Color(0xFFf9f8fd),
     child: Center(
       child: Container(
         constraints: BoxConstraints(maxWidth: 600),
         child: Column(
           children: [
             StageImage(),
             StageTextBlock(),
           ],
         ),
       ),
     ),
   );
 }
}

Die letzte Herausforderung ist das saubere, responsive Umbrechen des Textes in der Stage. Leider kommt es bei der Nutzung von Text-Widgets häufig vor, dass Texte nicht optimal umbrechen. Flutter trennt Wörter meistens nicht mit korrekter Silbentrennung. Deshalb benötigt das Elternelement eine fest definierte Breite. Das sollte man allerdings mit Blick auf eine hohe Responsivität vermeiden. Auch die dynamische Berechnung von MediaQueries und fest definierten Faktoren ist auf Dauer umständlich.

Hier hilft das RichText-Widget, das den Text und den zugehörigen Style als TextSpan übergibt. Knackpunkt ist hierbei dessen softWrap-Parameter, der auf true gesetzt wird. Das Ergebnis: ein automatisch richtig und sauber umgebrochener Text:

class StageSubline extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
   return RichText(
     text: TextSpan(
       text:
           'Running out of space in your head? 
           You don\'t know where to put all your ideas and creativity?',
       style: AppTextStyles.regularText,
     ),
     softWrap: true,
   );
 }
}

So sieht das Praxisbeispiel am Ende aus:

Desktop-Browser- und Mobile-App-Ansicht im Vergleich (Abb. 3)

Der Clou: der Code funktioniert sowohl als responsive Website, als auch als App auf dem Handy – hier zu sehen im iOS-Simulator unter macOS.

Mobile-Browser- und Mobile-App-Ansicht im Vergleich (Abb. 4)