Mobile Apps4 - FlutterWidgets ohne State

Widgets ohne State

💡

Dauer: 40 Minuten

  • Widgets sind UI-Komponenten
  • Styles verwenden
  • Checkbox, InkWell und ListView einbauen

Ziel: Umgang mit stateless Widgets vertiefen

In Android hatten wir es mit Composables zu tun, in Flutter heißen die UI-Komponenten Widgets.

Stateless Widgets

Ein stateless Widget ist eine Klasse, die von StatelessWidget erbt und die Methode build implementiert. Wir sehen dies in unserem Code sowohl mit der Klasse MyApp als auch mit der Klasse MyHomePage:

class MyApp extends StatelessWidget { 
  
  @override
  Widget build(BuildContext context) {
    // Code weggelassen
    // return Widget
  }
}
 
class MyHomePage extends StatelessWidget { 
 
  @override
  Widget build(BuildContext context) {
    // Code weggelassen
    // return Widget
  }
}

Ein stateless Widget ist unveränderlich, d.h. es kann nicht während der Laufzeit geändert werden. Das bedeutet, dass die UI-Komponenten, die in der Methode build erstellt werden, nicht verändert werden können.

TodoItem als StatelessWidget

Wir erstellen nun die Klasse TodoItem als stateless Widget in einer neuen Datei lib/todo_item.dart:

// Achtung: neue Datei lib/todo_item.dart !
import 'package:flutter/material.dart';
 
class TodoItem extends StatelessWidget {
  final String title;
 
  const TodoItem({super.key, required this.title});
 
  @override
  Widget build(BuildContext context) {
    return Text(title);
  }
}

TodoItem wird in der Klasse MyHomePage verwendet, dazu müssen wir zunächst die Datei todo_item.dart importieren:

import 'package:flutter/material.dart';
// Achtung: Import der neuen Datei lib/todo_item.dart !
import 'package:myapp/todo_item.dart';
 
void main() {
  runApp(const MyApp());
}
 
// Code weggelassen
// In der Klasse MyHomePage:
 
      body: const Column(
        children: [
          TodoItem(title: 'Einkaufen'), // anstatt Text-Widget
          TodoItem(title: 'Kochen'),
          TodoItem(title: 'Sport'),
        ],
      ),
 
// Code weggelassen

Styles in TodoItem

In Flutter gibt es viele Möglichkeiten, Styles zu definieren. Hier ein paar Beispiele (Vorschlag kam von ChatGPT):

import 'package:flutter/material.dart';
 
class TodoItem extends StatelessWidget {
  final String title;
 
  const TodoItem({super.key, required this.title});
 
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 2.0),
      child: Text(
        title,
        style: const TextStyle(fontSize: 18),
      ),
    );
  }
}

TextStyle definiert die Schriftart und -größe, EdgeInsets definiert den Abstand um das Widget herum. In unserem Beispiel haben wir einen vertikalen Abstand von 2 Pixeln (jeweils oben und unten) sowie eine Schriftgröße von 18 Pixeln definiert.

Checkbox in TodoItem

Wir können das TodoItem-Widget erweitern, um eine Checkbox hinzuzufügen:

class TodoItem extends StatelessWidget {
  final String title;
 
  const TodoItem({super.key, required this.title});
 
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 2.0),
      child: Row(
        children: [
          Checkbox(
            value: false,
            onChanged: (bool? value) { /* to be implemented */},
          ),
          Text(
            title,
            style: const TextStyle(fontSize: 18),
          ),
        ],
      ),
    );
  }
}

Wir implementieren die Methode onChanged später, wenn wir stateful Widgets behandeln.

Mit einer weiteren Anpassung wollen wir das ganze TodoItem antippbar machen:

// Code weggelassen
  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: () {/* to be implemented */},
      child: Padding(
        padding: const EdgeInsets.symmetric(vertical: 2.0),
        child: Row(
          children: [
            Checkbox(
              value: false,
              onChanged: (bool? value) {/* to be implemented */},
            ),
            Text(
              title,
              style: const TextStyle(fontSize: 18),
            ),
          ],
        ),
      ),
    );
  }

Hierzu verwenden wir das InkWell-Widget, das eine Berührung erkennt, darauf reagiert und visuelles Feedback gibt.

Es fällt auf, dass wir in Flutter weniger Import-Anweisungen benötigen als in der nativen Android-Entwicklung mit Kotlin.

TodoList-Widget mit ListView

Schließlich ersetzen wir Column für unsere drei statischen Todos durch ein ListView-Widget, um die TodoListe durch ein besseres Listen-Widget für mögliche große Todolisten zu optimieren und u.a. scrollbar zu machen.

Dazu erstellen wir zunächst eine weiteres stateless Widget in einer neuen Datei lib/todo_list.dart:

import 'package:flutter/material.dart';
import 'package:myapp/todo_item.dart';
 
class TodoList extends StatelessWidget {
  const TodoList({super.key});
 
  @override
  Widget build(BuildContext context) {
    return ListView(
      children: const [
        TodoItem(title: 'Einkaufen'),
        TodoItem(title: 'Kochen'),
        TodoItem(title: 'Sport'),
      ],
    );
  }
}

In lib/main.dart ersetzen wir den Import vom TodoItem mit TodoList und verwenden das neue Widget in der MyHomePage-Klasse:

import 'package:flutter/material.dart';
// Achtung: folgenden Import anpassen!
import 'package:myapp/todo_list.dart';
 
// Code weggelassen
 
class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});
 
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Todo-App'),
      ),
      body: const TodoList(), // Column durch TodoList ersetzt
      floatingActionButton: FloatingActionButton(
        onPressed: () => debugPrint('Todo hinzufügen'),
        tooltip: 'Todo hinzufügen',
        child: const Icon(Icons.add),
      ),
    );
  }
}

Zusammenfassung

In Flutter haben wir nun stateless Widgets kennengelernt, die als Dart-Klassen implementiert werden, von StatelessWidget erben und die Methode build implementieren. Es gibt viele vordefinierte Widgets in Flutter für UI-Komponenten, Styles, Layout usw.. Geschachtelte Widgets ergeben eine Baumstruktur, die das UI repräsentiert. Auch wenn in nativer Android-Entwicklung mit Kotlin und Compose die UI-Komponenten als Funktionen (Composables) definiert werden, gibt es viele Parallelen zwischen den beiden Frameworks.

Mehr zu Widgets in der Flutter-Dokumentation:

PAUSE

spätestens hier eine Pause einlegen