4.2 Punktezähler erstellen (inkl. Theorie zu Listen)
Sie werden einen Punktezähler erstellen, um nachzuverfolgen, wie viele Aussagen richtig und wie viele falsch beantwortet wurden. Scrollen Sie in Ihrer main.dart Datei bis zu dem Kommentar // hier folgt ein Row-Widget zur Speicherung des Punktestandes. und ersetzen Sie diesen Kommentar mit dem folgenden Code:
// 1
Row(
children: [
// 2
Icon(
Icons.check,
color: Colors.green,
),
// 2
Icon(
Icons.close,
color: Colors.red,
),
// 2
Icon(
Icons.check,
color: Colors.green,
),
// 2
Icon(
Icons.check,
color: Colors.green,
)
],
)
- Der Punktezähler besteht aus einem Row-Widget, welches in das Column-Widget integriert wird. Der Konstruktor des Row-Widgets besitzt einen children-Parameter, an welchen eine Liste übergeben wird.
- Die Liste setzt sich aus einer Reihe von grünen und roten Icon-Widgets zusammen.
Theorie
Listen
In der Programmierung werden Listen dazu verwendet, zusammengehörige Daten zu gruppieren. In Dart lässt sich eine Liste mit dem Schlüsselwort List erstellen. In diesem Code-Beispiel wird eine leere Liste erstellt.
List liste1 = [];
Analog zu Python können wir in diese Liste Objekte von unterschiedlichen Datentypen integrieren.
List liste2 = [1, 'hello', true];
Wenn wir den Datentyp eingrenzen möchten (damit nur Objekte von einem bestimmten Datentyp in einer Liste untergebracht werden können), können wir das nach dem List Schlüsselwort mit spitzen Klammern <> tun. Die Angabe des Datentyps macht unsere Liste viel sicherer, da wir nicht versehentlich Objekte vom falschen Datentyp in die Liste einfügen können.
List<String> liste3 = ['hi', 'my', 'name', 'is'];
List<int> liste4 = [3, 2, 1];
Mit der add()-Methode kann man Elemente zu einer Liste hinzufügen.
liste4.add(0);
print(liste4); // erzeugt Ausgabe: [3, 2, 1, 0]
Fügen Sie direkt unterhalb von class _QuizPageState extends State { diesen Code ein:
List<Icon> scoreKeeper = [];
Den Code für die Erstellung der Punktezähler-Icons gliedern wir in eine Liste mit dem Namen scoreKeeper aus. Diese Liste akzeptiert als Listenelemente nur Icon-Widgets. Die Punktezähler-Icons in einer separate Liste zu verwalten hat den Vorteil, dass man im Handumdrehen neue Icon-Widgets zur Liste hinzufügen kann.
Damit jetzt Icons zur scoreKeeper-Liste hinzugefügt werden, sobald Benutzer:innen die Schaltfläche Wahr oder Falsch antippen, müssen Sie in Ihrer Datei zu den Kommentaren // hier folgt die Aktion, falls User Wahr ausgewählt hat. und // hier folgt die Aktion, falls User Falsch ausgewählt hat. scrollen und durch
setState(() {
scoreKeeper.add(Icon(Icons.check, color: Colors.green));
});
und
setState(() {
scoreKeeper.add(Icon(Icons.close, color: Colors.red));
});
ersetzen.
Beide scoreKeeper.add-Methoden müssen in eine setState-Methode, damit der Widget-Baum bei jedem Antippen neu aufgebaut wird. Die scoreKeeper-Liste müssen Sie anschliessend als Kind an das Row-Widget übergeben. Also löschen Sie im Row-Widget die Liste mit den einzelnen Icon-Widgets durch den Code children: scoreKeeper, .
Mit diesen Anpassungen müsste Ihre main.dart-Datei folgendermassen aussehen:
import 'package:flutter/material.dart';
void main() {
runApp(QuizApp());
}
class QuizApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.grey.shade900,
body: SafeArea(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 10.0),
child: QuizPage(),
),
),
),
);
}
}
class QuizPage extends StatefulWidget {
@override
_QuizPageState createState() => _QuizPageState();
}
// 1
class _QuizPageState extends State {
List<Icon> scoreKeeper = [];
@override
Widget build(BuildContext context) {
// 2
return Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// 3
Expanded(
flex: 5,
child: Padding(
padding: EdgeInsets.all(10.0),
child: Center(
child: Text(
'Hier erscheinen die Aussagen.',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 25.0,
color: Colors.white,
),
),
),
),
),
// 3
Expanded(
child: Padding(
padding: EdgeInsets.all(15.0),
child: TextButton(
style: TextButton.styleFrom(backgroundColor: Colors.green),
child: Text(
'Wahr',
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
),
),
onPressed: () {
setState(() {
scoreKeeper.add(Icon(Icons.check, color: Colors.green));
});
},
),
),
),
// 3
Expanded(
child: Padding(
padding: EdgeInsets.all(15.0),
child: TextButton(
style: TextButton.styleFrom(backgroundColor: Colors.red),
child: Text(
'Falsch',
style: TextStyle(
fontSize: 20.0,
color: Colors.white,
),
),
onPressed: () {
setState(() {
scoreKeeper.add(Icon(Icons.close, color: Colors.red));
});
},
),
),
),
// 1
Row(
children: scoreKeeper,
)
],
);
}
}
Wenn Sie anschliessend die App ausführen wird mit einem Klick auf Wahr oder Falsch im unteren Bildschirmrand jeweils das entsprechende Icon erscheinen. Diese Funktionalität ergibt jedoch noch nicht so viel Sinn, da die check– und close-Icons später andeuten sollten, ob die Frage korrekt oder falsch beantwortet wurde.
Hier ging es in erster Linie einfach mal darum zu zeigen, wie sich eine Liste durch die Interaktion von Benutzer:innen erweitern lässt.
import ‘package:flutter/material.dart’;
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.grey.shade900,
body: const SafeArea(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 10.0),
child: QuizPage(),
),
),
),
);
}
}
class QuizPage extends StatefulWidget {
const QuizPage({Key? key}) : super(key: key);
@override
_QuizPageState createState() => _QuizPageState();
}
class _QuizPageState extends State {
List scoreKeeper = [];
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.stretch,
children:
[
const Expanded(
flex: 5,
child: Padding(
padding: EdgeInsets.all(10.0),
child: Center(
child: Text(
‘Hier erscheinen die Aussagen.’,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 25.0,
color: Colors.white,
),
),
),
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(15.0),
child: TextButton(
style: TextButton.styleFrom(backgroundColor: Colors.green),
child: const Text(
‘Wahr’,
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
),
),
onPressed: () {
setState(() {
scoreKeeper.add(const Icon(Icons.check, color: Colors.green));
});
},
),
),
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(15.0),
child: TextButton(
style: TextButton.styleFrom(backgroundColor: Colors.red),
child: const Text(
‘Falsch’,
style: TextStyle(
fontSize: 20.0,
color: Colors.white,
),
),
onPressed: () {
setState(() {
scoreKeeper.add(const Icon(Icons.close, color: Colors.red));
});
},
),
),
),
Row
(
children: scoreKeeper,
)
],
);
}
}
Lieber Niko, vielen Dank für Ihre Unterstützung. Natürlich wäre es besser mit const keywords zu arbeiten, aber wir haben der Einfachheit halber darauf verzichtet. Der Fehler in diesem Abschnitt war, dass in der Zeile mit List scoreKeeper = []; der Datentyp Icon in den spitzen Klammern gefehlt hatte. -KA