Flutter: Anpassung von Grid-Layouts an Device-Orientation und Screen-Größe

Ralf Weinbrecher
Apr 26 · 4 min read

In einem aktuellen Projekt bestand die Aufgabe darin, Information auf unterschiedlichen Screen-Formaten und sowohl in Portrait- als auch Landscape-Orientierung optimal darzustellen.

Flutter macht es einem leicht, Layouts an verschiedene Screen-Größen anzupassen. Dabei kommt die modulare Architektur, die Aufteilung in Widgets zum tragen.

Sehr universell und für viele Projektre verwendbare Widgets sind GridViews. Diesen Typen von Widgets können vielfältig verwendet werden. GridViews lassen auch eine sehr flexible Anpassung an Verschiedene Device-Größen und Orientierungen (Portrait- oder Landscape-Mode) zu. In diesem Artikel möchte ich an einem Beispiel zeigen, wie man ein GridView-Widget, in diesem Fall ein SliverGrid, konfiguriert, so dass es sich automatisch an Verschiedene Screen-Größen und wechselnde Orientierung, also Drehungen des Bildschirms, anpasst.

Bestimmung der Screen-Größe

Für die korrekte Darstellung des Grid auf den unterschiedlichen Screen-Größen ist es notwendig, die Dimensionen des Bildschirms zu bestimmen:

int screenHeight = MediaQuery.of(context).size.height;
int screenWidth = MediaQuery.of(context).size.width;

Damit lassen sich im Code Verzweigungen integrieren, um nach Screen-Größe zu unterscheiden. Um z.B. zwischen Smartphone und Tablet zu unterscheiden, kann man etwa folgende Abfrage einsetzen:

if (MediaQuery.of(context).site.width > 600) {
... // Tablet-Layout
} else {
... // Phone-Layout
}

Die Annahme, dass alle Bildschirme mit einer Zahl von mehr als 600 Pixeln in der Horizontalen ein Tablet sein müssen, greift natürlich zu kurz. Moderne SmartPhones in Landscape-Orientierung fallen ebenfalls in diese Kategorie.

Phone oder Tablet?

Zur Bestimmung des Gerätetyps kann das Flutter-Package flutter_device_type verwendet werden.

Mit diesem Package gelingt die Bestimmung der Geräte-Kategorie einfach und präzise.

import 'package:flutter_device_type/flutter_device_type.dart';if (Device.get().isTablet) {
... // Tablet-Layout
} else {
... // Phone-Layout
}

Mit Hilfe des Package können noch einige weitere Device-Properties bestimmt werden, aber für die Zwecke dieses Beispiels reicht das bereits aus.

Definition des Layout

Für das Beispiel soll ein GridView zum Einsatz kommen. Auf Phones im Portrait-Mode soll das Layout einspaltig sein, d.h. wie ein gewöhnlicher ListView wirken. Im Landscape-Mode soll auf dem Phone-Screen das Grid zwei Spalten aufweisen.

Zweispaltiges Grid-Layout auf dem Phone im Landscape-Mode
Einspaltiges Layout im Portrait-Mode

Auf dem Tablet-Screen soll das Grid im Portrait-Mode zwei Spalten anzeigen und in Landscape-Orientierung drei Spalten darstellen. Bei Wechsel zwischen den Orientierungen soll das Layout neu aufgebautr werden.

Tablet im Landscape-Modus mit Drei-Spalten-Grid
Tablet mit zweispaltigem Layout im Portrait-Mode

Für den Aufbau des GridView sind zwei Parameter entscheidend:

Höhe der Elemente

Im SliverGrid-Widget kann die Höhe eines Elements nicht direkt festgelegt werden, stattdessen wird die Geometrie über das Seitenverhältnis der Elemente (Aspect Ratio) definiert.

final num itemHeight = _heightOfItem(context);

Jedes Mal, wenn das Widget neu gerendert wird, wird dieser Parameter erneut berechnet. Die Funktion zur Berechnung des Parameters ist folgendermaßen aufgebaut:

num _heightOfItem(BuildContext context) {
num itemHeight;
if (Device.get().isTablet) {
if (MediaQuery.of(context).orientation
== Orientation.portrait) {
itemHeight = (MediaQuery.of(context).size.height - 200.0) / 5;
} else {
itemHeight = (MediaQuery.of(context).size.height - 200.0) / 3;
}
} else {
itemHeight = 150.0;
}
return itemHeight;
}

Anzahl der Spalten

Für dieses Beispiel ist es erforderlich, je nach Orientierung und Gerätetyp die Zahl der Spalten im Layout zu bestimmen.

final int numberOfColumns = _numberOfGridColumns(context);

Auch dieser Parameter wird beim Neu-Generieren des Widgets bestimmt. Der Code dazu sieht so aus:

int _numberOfGridColumns(BuildContext context) {  int numberOfColumns = 0;  if (Device.get().isTablet) {
if (MediaQuery.of(context).orientation
== Orientation.portrait) {
numberOfColumns = 2;
} else {
numberOfColumns = 3;
}
} else {
if (MediaQuery.of(context).orientation
== Orientation.portrait) {
numberOfColumns = 1;
} else {
numberOfColumns = 2;
}
}
return numberOfColumns;
}

Konfiguration des SliverGrid-Widget

Mit diesen für die Konfiguration wichtigen Parametern kann das SliverGrid-Widget konstruiert werden:

SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount
crossAxisCount: numberOfColumns,
childAspectRatio: MediaQuery.of(context).size.width
/numberOfColumns / itemHeight
),
delegate: SliverChildBuilderDelegate((BuildContext context,
int index) {
return Container(
color: _getRandomColor(),
);
},
childCount: 20,
),
),

Der Parameter childCount wurde hier willkürlich auf 20 gesetzt. Der Wert spielt im Zusammenhang mit dem Beispiel keine Rolle. Bei Wechsel der Orientierung passt sich das Layout des Widgets den vorgegebenen Werten an.

Der komplette Source-Code des Beispiel-Projekts ist auf Github verfügbar.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade