MDC-103 Flutter: Material Theming mit Farbe, Form, Höhe und Typ

1. Einführung

logo_components_color_2x_web_96dp.png

Material Components (MDC) unterstützen Entwickler bei der Implementierung von Material Design. MDC wurde von einem Team aus Entwicklern und UX-Designern bei Google entwickelt. Es enthält Dutzende schöne und funktionale UI-Komponenten und ist für Android, iOS, das Web und Flutter.material.io/develop verfügbar.

Du kannst jetzt Material Flutter verwenden, um die unverwechselbaren Stil entwickeln. Die jüngste Erweiterung von Material Design bietet Designschaffenden und Entwickelnden mehr Flexibilität, die Marke ihres Produkts zum Ausdruck zu bringen.

In den Codelabs MDC-101 und MDC-102 haben Sie mithilfe von Material Flutter die Grundlagen einer App namens Shrine entwickelt. Das ist eine E-Commerce-App für den Verkauf von Kleidung und Haushaltswaren. Diese App enthält einen User Flow, der mit einem Anmeldebildschirm beginnt und den Nutzer dann zu einem Startbildschirm mit Produkten weiterleitet.

Inhalt

In diesem Codelab kannst du die Shrine-App anpassen:

  • Farbe
  • Typografie
  • Höhe
  • Form
  • Layout

Android

iOS

Anmeldeseite für Schrein, Design braun und rosa

Anmeldeseite für Schrein, Design braun und rosa

Shrine-Produktseite mit einer oberen App-Leiste und einem asymmetrischen, horizontal scrollbaren Raster voller Produkte, das Thema Rosa

Codelab: Material Flutter-Komponenten und -Subsysteme

  • Designs
  • Typografie
  • Höhe
  • Bildliste

Wie würden Sie Ihre Erfahrung mit der Flutter-Entwicklung bewerten?

<ph type="x-smartling-placeholder"></ph> Neuling Mittel Kompetent

2. Flutter-Entwicklungsumgebung einrichten

Für dieses Lab benötigen Sie zwei Softwareprogramme: das Flutter SDK und einen Editor.

Sie können das Codelab auf jedem dieser Geräte ausführen:

  • Ein physisches Android- oder iOS, das mit Ihrem Computer verbunden ist und sich im Entwicklermodus befindet.
  • Den iOS-Simulator (erfordert die Installation von Xcode-Tools).
  • Android-Emulator (Einrichtung in Android Studio erforderlich)
  • Ein Browser (zur Fehlerbehebung wird Chrome benötigt)
  • Als Windows-, Linux- oder macOS-Desktopanwendung Die Entwicklung muss auf der Plattform erfolgen, auf der Sie die Bereitstellung planen. Wenn Sie also eine Windows-Desktop-App entwickeln möchten, müssen Sie die Entwicklung unter Windows ausführen, damit Sie auf die entsprechende Build-Kette zugreifen können. Es gibt betriebssystemspezifische Anforderungen, die unter docs.flutter.dev/desktop ausführlich beschrieben werden.

3. Codelab-Starter-App herunterladen

Weiter mit MDC-102?

Wenn Sie MDC-102 abgeschlossen haben, sollte Ihr Code für dieses Codelab bereit sein. Fahren Sie mit dem Schritt Farben ändern fort.

Neu beginnen?

Starter-Codelab-App herunterladen

Die Start-App befindet sich im Verzeichnis material-components-flutter-codelabs-103-starter_and_102-complete/mdc_100_series.

...oder von GitHub klonen

Führen Sie die folgenden Befehle aus, um dieses Codelab von GitHub zu klonen:

git clone https://github.com/material-components/material-components-flutter-codelabs.git
cd material-components-flutter-codelabs/mdc_100_series
git checkout 103-starter_and_102-complete

Projekt öffnen und App ausführen

  1. Öffnen Sie das Projekt in einem Editor Ihrer Wahl.
  2. Folgen Sie der Anleitung zum Ausführen der App. unter Erste Schritte: Testlauf für den ausgewählten Editor.

Fertig! Auf deinem Gerät sollte nun die Anmeldeseite von Shrine aus den vorherigen Codelabs angezeigt werden.

Android

iOS

Anmeldeseite des Schreins ohne Design

Anmeldeseite des Schreins ohne Design

Klicken Sie auf „Weiter“. um die Produktseite aufzurufen.

Android

iOS

Shrine-Produktraster-Seite ohne Thema

Shrine-Produktraster-Seite ohne Thema

4. Farben ändern

Es wurde ein Farbschema erstellt, das die Marke Shrine repräsentiert. Der Designer bittet Sie, dieses Farbschema in der Shrine-App zu implementieren.

Zunächst importieren wir diese Farben in unser Projekt.

Erstellen colors.dart

Erstellen Sie in lib eine neue Dart-Datei mit dem Namen colors.dart. Importieren Sie material.dart und fügen Sie const Color-Werte hinzu:

import 'package:flutter/material.dart';

const kShrinePink50 = Color(0xFFFEEAE6);
const kShrinePink100 = Color(0xFFFEDBD0);
const kShrinePink300 = Color(0xFFFBB8AC);
const kShrinePink400 = Color(0xFFEAA4A4);

const kShrineBrown900 = Color(0xFF442B2D);

const kShrineErrorRed = Color(0xFFC5032B);

const kShrineSurfaceWhite = Color(0xFFFFFBFA);
const kShrineBackgroundWhite = Colors.white;

Benutzerdefinierte Farbvorlage

Dieses Farbdesign wurde von einem Designer mit benutzerdefinierten Farben erstellt (siehe Bild unten). Sie enthält Farben, die aus der Marke Shrine ausgewählt und auf den Material Theme Editor angewendet wurden. Dieser hat sie erweitert, um eine umfassendere Palette zu erstellen. (Diese Farben stammen nicht aus den Farbvorlagen für Material von 2014.)

Im Material Theme Editor wurden sie in Schattierungen mit numerisch beschrifteten Schattierungen organisiert, einschließlich der Beschriftungen 50, 100, 200, ... bis 900 jeder Farbe. Shrine verwendet nur die Farbtöne 50, 100 und 300 aus dem rosa und 900 aus dem braunen Farbmuster.

d0362cb45c565a8e.jpeg 470b0e1c2669ae2.png

Jeder Farbparameter eines Widgets wird einer Farbe aus diesen Schemas zugeordnet. Beispielsweise sollte die Farbe für die Dekoration eines Textfeldes, wenn aktiv Eingaben empfängt, die Primärfarbe des Designs sein. Ist diese Farbe nicht barrierefrei (gut erkennbar auf dem Hintergrund) vorhanden, verwenden Sie stattdessen eine andere Farbe.

Da wir nun die gewünschten Farben haben, können wir sie auf die Benutzeroberfläche anwenden. Dazu legen wir die Werte eines ThemeData-Widgets an, das wir auf die MaterialApp-Instanz ganz oben in unserer Widget-Hierarchie anwenden.

ThemeData.light() anpassen

Es gibt einige integrierte Designs für Flutter. Das helle Design ist eines davon. Anstatt ein ThemeData-Widget von Grund auf neu zu erstellen, kopieren wir das helle Design und ändern die Werte, um sie für unsere App anzupassen.

Importieren Sie colors.dart in app.dart.

import 'colors.dart';

Fügen Sie dann Folgendes zu app.dart außerhalb des Bereichs der ShrineApp-Klasse hinzu:

// TODO: Build a Shrine Theme (103)
final ThemeData _kShrineTheme = _buildShrineTheme();

ThemeData _buildShrineTheme() {
  final ThemeData base = ThemeData.light(useMaterial3: true);
  return base.copyWith(
    colorScheme: base.colorScheme.copyWith(
      primary: kShrinePink100,
      onPrimary: kShrineBrown900,
      secondary: kShrineBrown900,
      error: kShrineErrorRed,
    ),
    // TODO: Add the text themes (103)
    // TODO: Decorate the inputs (103)
  );
}

Legen Sie nun theme: am Ende der Funktion build() von ShrineApp (im MaterialApp-Widget) als neues Design fest:

  // TODO: Customize the theme (103)
  theme: _kShrineTheme, // New code

Projekt speichern. Ihr Anmeldebildschirm sollte nun so aussehen:

Android

iOS

Anmeldeseite eines Schreins mit rosa und braunem Design

Anmeldeseite eines Schreins mit rosa und braunem Design

5. Typografie und Labelstile ändern

Neben den Farbänderungen haben uns die Designschaffenden auch spezifische Typografie zur Verfügung gestellt. „ThemeData“ von Flutter umfasst drei Textthemen. Jedes Textdesign besteht aus einer Sammlung von Textstilen, z. B. „Anzeigentitel“. und „title“. Wir verwenden einige Stile für unsere App und ändern einige der Werte.

Textdesign anpassen

Schriftarten müssen der Datei pubspec.yaml hinzugefügt werden, um sie in das Projekt zu importieren.

Fügen Sie in der Datei pubspec.yaml direkt nach dem Tag flutter: Folgendes hinzu:

  # TODO: Insert Fonts (103)
  fonts:
    - family: Rubik
      fonts:
        - asset: fonts/Rubik-Regular.ttf
        - asset: fonts/Rubik-Medium.ttf
          weight: 500

Du kannst jetzt auf die Schriftart „Rubik“ zugreifen und sie verwenden.

Fehlerbehebung für die pubspec-Datei

Wenn Sie die Deklaration ausschneiden und einfügen, können beim Ausführen von pub get Fehler auftreten. Wenn Fehler auftreten, entfernen Sie zuerst das führende Leerzeichen und ersetzen Sie es durch Einrückung von zwei Leerzeichen durch Leerzeichen. (Zwei Leerzeichen vor

fonts:

, vier Leerzeichen davor

family: Rubik

usw.)

Wenn die Meldung Zuordnungswerte sind hier nicht zulässig angezeigt wird, überprüfen Sie den Einzug der Zeile, in der das Problem auftritt, und die Einrückung der Zeilen darüber.

Ändern Sie in login.dart Folgendes innerhalb von Column():

Column(
  children: <Widget>[
    Image.asset('assets/diamond.png'),
    const SizedBox(height: 16.0),
    Text(
      'SHRINE',
      style: Theme.of(context).textTheme.headlineSmall,
    ),
  ],
)

Fügen Sie in app.dart nach _buildShrineTheme() Folgendes ein:

// TODO: Build a Shrine Text Theme (103)
TextTheme _buildShrineTextTheme(TextTheme base) {
  return base
      .copyWith(
        headlineSmall: base.headlineSmall!.copyWith(
          fontWeight: FontWeight.w500,
        ),
        titleLarge: base.titleLarge!.copyWith(
          fontSize: 18.0,
        ),
        bodySmall: base.bodySmall!.copyWith(
          fontWeight: FontWeight.w400,
          fontSize: 14.0,
        ),
        bodyLarge: base.bodyLarge!.copyWith(
          fontWeight: FontWeight.w500,
          fontSize: 16.0,
        ),
      )
      .apply(
        fontFamily: 'Rubik',
        displayColor: kShrineBrown900,
        bodyColor: kShrineBrown900,
      );
}

Dadurch wird anhand eines TextTheme-Elements das Aussehen der Überschriften, Titel und Untertitel geändert.

Wenn Sie fontFamily auf diese Weise anwenden, werden die Änderungen nur auf die in copyWith() angegebenen Werte für die typografische Skala angewendet (Anzeigentitel, Titel, Untertitel).

Für einige Schriftarten legen wir eine benutzerdefinierte Schriftstärke in Schritten von 100 fest: W500 (die Schriftstärke 500) entspricht mittel und w400 der Normalgröße.

Die neuen Text Hemes verwenden

Fügen Sie _buildShrineTheme nach dem Fehler die folgenden Designs hinzu:

// TODO: Add the text themes (103)
textTheme: _buildShrineTextTheme(base.textTheme),
textSelectionTheme: const TextSelectionThemeData(
  selectionColor: kShrinePink100,
),

Projekt speichern. Da wir die Schriftarten geändert haben, müssen Sie diesmal auch die App neu starten (Hot Neustart).

Android

iOS

Shrine-Produktrasterseite mit angewendeten Textdesigns

Der Text auf dem Anmelde- und Startbildschirm sieht anders aus: Einige Texte verwenden die Schriftart Rubik, während anderer Text braun statt schwarz oder weiß gerendert wird. Symbole werden ebenfalls braun dargestellt.

Text verkleinern

Die Labels sind zu groß.

Ändern Sie in home.dart den children: der innersten Spalte:

// TODO: Change innermost Column (103)
children: <Widget>[
// TODO: Handle overflowing labels (103)
  Text(
    product.name,
    style: theme.textTheme.button,
    softWrap: false,
    overflow: TextOverflow.ellipsis,
    maxLines: 1,
  ),
  const SizedBox(height: 4.0),
  Text(
    formatter.format(product.price),
    style: theme.textTheme.bodySmall,
  ),
  // End new code
],

Text zentrieren und ablegen

Wir möchten die Beschriftungen zentrieren und den Text am unteren Rand jeder Karte ausrichten und nicht am unteren Rand jedes Bildes.

Verschieben Sie die Beschriftungen an das Ende (unten) der Hauptachse und legen Sie fest, dass sie zentriert sind:

  // TODO: Align labels to the bottom and center (103)
  mainAxisAlignment: MainAxisAlignment.end,
  crossAxisAlignment: CrossAxisAlignment.center,

Projekt speichern.

Android

iOS

Shrine-Produktraster-Seite mit unterschiedlicher Textausrichtung

Shrine-Produktraster-Seite mit unterschiedlicher Textausrichtung

Das sieht viel besser aus.

Design der Textfelder

Sie können die Gestaltung von Textfeldern auch mit InputDecorationTheme gestalten.

Geben Sie in app.dart in der Methode _buildShrineTheme() einen inputDecorationTheme:-Wert an:

// TODO: Decorate the inputs (103)
inputDecorationTheme: const InputDecorationTheme(
  border: OutlineInputBorder(),
),

Im Moment sind die Textfelder filled-dekoriert. Das entfernen wir. Wenn Sie filled entfernen und inputDecorationTheme angeben, erhalten die Textfelder den Umrissstil.

Entfernen Sie in login.dart die Werte für filled: true:

// Remove filled: true values (103)
TextField(
  controller: _usernameController,
  decoration: const InputDecoration(
    // Removed filled: true
    labelText: 'Username',
  ),
),
const SizedBox(height: 12.0),
TextField(
  controller: _passwordController,
  decoration: const InputDecoration(
    // Removed filled: true
    labelText: 'Password',
  ),
  obscureText: true,
),

Neustart. Ihr Anmeldebildschirm sollte wie folgt aussehen, wenn das Feld Nutzername aktiv ist (wenn Sie es eingeben):

Android

iOS

Anmeldeseite für Schrein mit hervorgehobenem Feld für Nutzernamen

Anmeldeseite für Schrein mit hervorgehobenem Feld für Nutzernamen

Geben Sie Text in ein Textfeld ein. Die Rahmen und unverankerten Labels werden in der Primärfarbe gerendert. Aber wir können es nicht so leicht sehen. Sie ist nicht zugänglich für Personen, die Probleme haben, Pixel mit einem nicht ausreichend hohen Farbkontrast zu unterscheiden. Weitere Informationen finden Sie im Artikel zu Farbe und Bedienungshilfen in den Materialrichtlinien.

Geben Sie in app.dart einen focusedBorder: unter inputDecorationTheme: an :

// TODO: Decorate the inputs (103)
inputDecorationTheme: const InputDecorationTheme(
  border: OutlineInputBorder(),
  focusedBorder: OutlineInputBorder(
    borderSide: BorderSide(
      width: 2.0,
      color: kShrineBrown900,
    ),
  ),
),

Geben Sie als Nächstes unter inputDecorationTheme: einen floatingLabelStyle: an :

// TODO: Decorate the inputs (103)
inputDecorationTheme: const InputDecorationTheme(
  border: OutlineInputBorder(),
  focusedBorder: OutlineInputBorder(
    borderSide: BorderSide(
      width: 2.0,
      color: kShrineBrown900,
    ),
  ),
  floatingLabelStyle: TextStyle(
    color: kShrineBrown900,
  ),
),

Zum Schluss verwenden wir für die Schaltfläche „Cancel“ (Abbrechen) die sekundäre Farbe anstelle der primären Farbe, um den Kontrast zu erhöhen.

TextButton(
  child: const Text('CANCEL'),
  onPressed: () {
    _usernameController.clear();
    _passwordController.clear();
  },
  style: TextButton.styleFrom(
    primary: Theme.of(context).colorScheme.secondary,
  ),
),

Projekt speichern.

Android

iOS

Anmeldeseite für Schrein mit zugänglicher Schaltfläche ABBRECHEN

Anmeldeseite für Schrein mit zugänglicher Schaltfläche ABBRECHEN

6. Höhe anpassen

Nachdem Sie nun die Seite mit einer Farbe und einer bestimmten Typografie gestaltet haben, die zum Schrein passen, passen wir nun die Höhe an.

Höhe der Schaltfläche „WEITER“ ändern

Die Standardhöhe für ElevatedButton ist 2. Erhöhen wir sie.

Fügen Sie in login.dart dem ElevatedButton NEXT einen style:-Wert hinzu:

ElevatedButton(
  child: const Text('NEXT'),
  onPressed: () {
    Navigator.pop(context);
  },
  style: ElevatedButton.styleFrom(
    foregroundColor: kShrineBrown900,
    backgroundColor: kShrinePink100,
    elevation: 8.0,
  ),
),

Projekt speichern.

Android

iOS

Anmeldeseite des Schreins mit erhöhter Schaltfläche WEITER

Anmeldeseite des Schreins mit erhöhter Schaltfläche WEITER

Höhe der Karte anpassen

Im Moment befanden sich die Karten auf einer weißen Fläche neben der Navigation der Website.

Füge in home.dart den Infokarten einen elevation:-Wert hinzu:

// TODO: Adjust card heights (103)
elevation: 0.0,

Speichern Sie das Projekt.

Android

iOS

Seite mit Shrine-Produktraster ohne Erhöhung für jede Karte

Seite mit Shrine-Produktraster ohne Erhöhung für jede Karte

Sie haben den Schatten unter den Karten entfernt.

7. Form hinzufügen

Der Schrein hat einen coolen geometrischen Stil und definiert Elemente durch eine achteckige oder rechteckige Form. Implementieren Sie nun diesen Formstil in den Karten auf dem Startbildschirm sowie in die Textfelder und Schaltflächen auf dem Anmeldebildschirm.

Formen von Textfeldern auf dem Anmeldebildschirm ändern

Importieren Sie in app.dart die folgende Datei:

import 'supplemental/cut_corners_border.dart';

Ändern Sie in app.dart das Design für das Design des Textfelds, um einen Rahmen mit ausgeschnittenen Ecken zu verwenden:

// TODO: Decorate the inputs (103)
inputDecorationTheme: const InputDecorationTheme(
  border: CutCornersBorder(),
  focusedBorder: CutCornersBorder(
    borderSide: BorderSide(
      width: 2.0,
      color: kShrineBrown900,
    ),
  ), 
  floatingLabelStyle: TextStyle(
    color: kShrineBrown900,
  ),
),

Schaltflächenformen auf dem Anmeldebildschirm ändern

Fügen Sie in login.dart der Schaltfläche ABBRECHEN einen abgeschrägten rechteckigen Rahmen hinzu:

TextButton(
  child: const Text('CANCEL'),
  onPressed: () {
    _usernameController.clear();
    _passwordController.clear();
  },
  style: TextButton.styleFrom(
    foregroundColor: kShrineBrown900,
    shape: const BeveledRectangleBorder(
      borderRadius: BorderRadius.all(Radius.circular(7.0)),
    ),
  ),
),

Der TextButton hat keine sichtbare Form. Warum sollte ich eine Rahmenform hinzufügen? Die Wellenanimation bleibt also beim Berühren an dieselbe Form gebunden.

Fügen Sie nun dieselbe Form zur Schaltfläche WEITER hinzu:

ElevatedButton(
  child: const Text('NEXT'),
  onPressed: () {
    Navigator.pop(context);
  },
  style: ElevatedButton.styleFrom(
    foregroundColor: kShrineBrown900,
    backgroundColor: kShrinePink100,
    elevation: 8.0,
    shape: const BeveledRectangleBorder(
      borderRadius: BorderRadius.all(Radius.circular(7.0)),
    ),
  ),
),

Um die Form aller Schaltflächen zu ändern, können wir auch elevatedButtonTheme oder textButtonTheme in app.dart verwenden. Das bleibt eine Herausforderung für den Lernenden.

Neustart.

Android

iOS

Anmeldeseite für Schrein mit angewendeter Formthema

Anmeldeseite für Schrein mit angewendeter Formthema

8. Layout ändern

Als Nächstes ändern wir das Layout, um die Karten mit unterschiedlichen Seitenverhältnissen und Größen anzuzeigen, sodass jede Karte von den anderen einzigartig aussieht.

GridView durch AsymmetricView ersetzen

Wir haben die Dateien für ein asymmetrisches Layout bereits geschrieben.

Fügen Sie in home.dart den folgenden Import hinzu:

import 'supplemental/asymmetric_view.dart';

Löschen Sie _buildGridCards und ersetzen Sie body:

body: AsymmetricView(
  products: ProductsRepository.loadProducts(Category.all),
),

Speichern Sie das Projekt.

Android

iOS

Shrine-Produktseite mit asymmetrischem, horizontal scrollbarem Layout

Shrine-Produktseite mit asymmetrischem, horizontal scrollbarem Layout

Jetzt scrollen die Produkte horizontal in einem gewebt inspirierten Muster.

9. Anderes Design ausprobieren (optional)

Farbe ist ein wirkungsvolles Mittel, um Ihre Marke auszudrücken, und eine kleine Farbänderung kann einen großen Einfluss auf die User Experience haben. Um dies zu testen, sehen wir uns an, wie Shrine aussieht, wenn das Farbschema der Marke etwas anders wäre.

Farben ändern

Fügen Sie in colors.dart die folgende Farbe hinzu:

const kShrinePurple = Color(0xFF5D1049);

Ändern Sie in app.dart die Funktion _buildShrineTheme() so:

ThemeData _buildShrineTheme() {
  final ThemeData base = ThemeData.light();
  return base.copyWith(
    colorScheme: base.colorScheme.copyWith(
      primary: kShrinePurple,
      secondary: kShrinePurple,
      error: kShrineErrorRed,
    ),
    scaffoldBackgroundColor: kShrineSurfaceWhite,
    textSelectionTheme: const TextSelectionThemeData(
      selectionColor: kShrinePurple,
    ),
    appBarTheme: const AppBarTheme(
      foregroundColor: kShrineBrown900,
      backgroundColor: kShrinePink100,
    ),

    inputDecorationTheme: const InputDecorationTheme(
      border: CutCornersBorder(),
      focusedBorder: CutCornersBorder(
        borderSide: BorderSide(
          width: 2.0,
          color: kShrinePurple,
        ),
      ),
      floatingLabelStyle: TextStyle(
        color: kShrinePurple,
      ),
    ),
  );
}

Neustart. Das neue Design sollte jetzt angezeigt werden.

Android

iOS

Anmeldeseite für einen Schrein in einem lila-rosa Design

Anmeldeseite für einen Schrein in einem lila-rosa Design

Android

iOS

Produktseite eines Schreins mit rosafarbenem Design

Produktseite eines Schreins mit rosafarbenem Design

Das Ergebnis sieht ganz anders aus. app.dart's _buildShrineTheme wird auf den Zustand vor diesem Schritt zurückgesetzt. Du kannst auch den Startcode von 104 herunterladen.

10. Glückwunsch!

Inzwischen haben Sie eine App erstellt, die den Designspezifikationen Ihrer Designfachkraft ähnelt.

Weiteres Vorgehen

Sie haben jetzt das folgende Material Flutter verwendet: Design, Typografie, Elevation und Form. In der Material Flutter-Bibliothek finden Sie weitere Komponenten und Subsysteme.

Sehen Sie sich die Dateien im Verzeichnis supplemental an, um zu erfahren, wie wir das horizontal scrollbare, asymmetrische Layoutraster erstellt haben.

Was ist, wenn Ihr geplantes App-Design Elemente enthält, für die keine Komponenten in der Bibliothek vorhanden sind? In MDC-104: Material Advanced Components wird gezeigt, wie Sie mithilfe der Material Flutter-Bibliothek benutzerdefinierte Komponenten erstellen, um den gewünschten Look zu erzielen.

Ich konnte dieses Codelab mit angemessenem Zeit- und Arbeitsaufwand abschließen

<ph type="x-smartling-placeholder"></ph> Stimme vollkommen zu Stimme zu Weder zufrieden noch unzufrieden Stimme nicht zu Stimme überhaupt nicht zu

Ich möchte Material Components weiterhin verwenden.

<ph type="x-smartling-placeholder"></ph> Stimme vollkommen zu Stimme zu Weder zufrieden noch unzufrieden Stimme nicht zu Stimme überhaupt nicht zu