MDC-103 Flutter: dopasowywanie motywu, kolor, kształt, wysokość i typ

1. Wprowadzenie

logo_components_color_2x_web_96dp.png

Material Komponenty (MDC) pomagają deweloperom wdrażać interfejs Material Design. MDC, stworzona przez zespół inżynierów i projektantów UX w Google, zawiera dziesiątki pięknych i funkcjonalnych komponentów interfejsu. Jest dostępny na Androida, iOS, internet oraz Flutter.material.io/develop

Teraz możesz używać Material Flutter, aby dostosowywać aplikacje charakterystyczny styl. Najnowsze rozszerzenie interfejsu Material Design daje projektantom i deweloperom większą elastyczność prezentowania marki produktu.

W ramach ćwiczeń z programowania MDC-101 i MDC-102 wykorzystaliśmy Material Flutter do stworzenia podstawowych elementów aplikacji o nazwie Shrine – aplikacji e-commerce, która umożliwia sprzedaż odzieży i artykułów gospodarstwa domowego. Ta aplikacja zawiera wzorzec przeglądania, który rozpoczyna się od ekranu logowania, a potem przenosi użytkownika na ekran główny, na którym wyświetlają się produkty.

Co utworzysz

W ramach tego ćwiczenia w programie dostosujesz aplikację Shrine za pomocą:

  • Kolor
  • Typografia
  • Wysokość
  • Kształt
  • Układ

Android

iOS

Strona logowania do świątyni z motywem brązowo-różowym

Strona logowania do świątyni z motywem brązowo-różowym

Strona produktu w świątyni z górnym paskiem aplikacji i asymetryczną, przewijaną w poziomie siatką pełną produktów z motywem różowym

Komponenty i podsystemy Material Flutter dostępne w tym ćwiczeniu z programowania

  • Motywy
  • Typografia
  • Wysokość
  • Lista obrazów

Jak oceniasz swój poziom doświadczenia w programowaniu w usłudze Flutter?

Początkujący Poziom średnio zaawansowany Biegły
.

2. Konfigurowanie środowiska programistycznego Flutter

Aby ukończyć ten moduł, potrzebujesz 2 oprogramowania: pakietu SDK Flutter i edytora.

Ćwiczenie z programowania możesz uruchomić na dowolnym z tych urządzeń:

  • Fizyczne urządzenie z Androidem lub iOS podłączone do komputera i ustawione w trybie programisty.
  • Symulator iOS (wymaga zainstalowania narzędzi Xcode).
  • Emulator Androida (wymaga skonfigurowania Android Studio).
  • Przeglądarka (do debugowania wymagany jest Chrome).
  • Aplikacja komputerowa w systemie Windows, Linux lub macOS Programowanie należy tworzyć na platformie, na której zamierzasz wdrożyć usługę. Jeśli więc chcesz opracować aplikację komputerową dla systemu Windows, musisz to zrobić w tym systemie, aby uzyskać dostęp do odpowiedniego łańcucha kompilacji. Istnieją wymagania związane z konkretnymi systemami operacyjnymi, które zostały szczegółowo omówione na stronie docs.flutter.dev/desktop.

3. Pobierz aplikację startową w Codelabs

Przechodzisz z MDC-102?

Jeśli masz ukończone wszystkie etapy MDC-102, Twój kod powinien być gotowy do wykorzystania w tym ćwiczeniu z programowania. Przejdź do kroku: Zmiana kolorów.

Zaczynasz od zera?

Pobierz aplikację startową z programowania

Aplikacja startowa znajduje się w katalogu material-components-flutter-codelabs-103-starter_and_102-complete/mdc_100_series.

...lub skopiuj je z GitHuba

Aby skopiować to ćwiczenia z programowania z GitHuba, uruchom te polecenia:

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

Otwieranie projektu i uruchamianie aplikacji

  1. Otwórz projekt w wybranym edytorze.
  2. Postępuj zgodnie z instrukcjami „Uruchom aplikację” w artykule Rozpocznij: jazdę próbną dla wybranego edytora.

Gotowe! Na urządzeniu powinna wyświetlić się strona logowania do Shrine z poprzednich ćwiczeń z programowania.

Android

iOS

niesformatowana strona logowania do świątyni

niesformatowana strona logowania do świątyni

Kliknij „Dalej” aby wyświetlić stronę produktu.

Android

iOS

nietematyczna strona siatki produktów Shrine

nietematyczna strona siatki produktów Shrine

4. Zmień kolory

Utworzono schemat kolorów, który reprezentuje markę Shrine, a projektant prosi Cię o wdrożenie go w aplikacji Shrine.

Na początek zaimportujmy te kolory do naszego projektu.

Utwórz colors.dart

Utwórz w grze lib nowy plik z rzutkami o nazwie colors.dart. Importuj material.dart i dodaj wartości const Color:

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;

Niestandardowa paleta kolorów

Ten motyw kolorystyczny został utworzony przez projektanta z niestandardowymi kolorami (widocznymi na ilustracji poniżej). Zawiera kolory, które zostały wybrane od marki Shrine i zastosowane w edytorze motywów Material Design, co spowodowało ich poszerzenie w celu uzyskania bogatszej palety. (Te kolory nie pochodzą z palet kolorów Material z 2014 roku).

W edytorze motywów materiałowych są pogrupowane według odcieni oznaczonych numerycznie, w tym od 50, 100, 200, ... do 900 kolorów każdego z nich. Świątynia używa tylko odcieni 50, 100 i 300 z różowej próbki oraz 900 z brązowej próbki.

d0362cb45c565a8e.jpeg 470b0e1c2669ae2.png

Każdy kolorowy parametr widżetu jest przyporządkowany do koloru z tych schematów. Na przykład kolor dekoracji pola tekstowego, gdy otrzymuje ono dane wejściowe, powinien być kolorem głównym motywu. Jeśli dany kolor jest niedostępny (jest dobrze widoczny na tle), użyj innego.

Po wybraniu kolorów, których chcemy używać, możemy je zastosować w interfejsie. Aby to zrobić, ustaw wartości widżetu ThemeData, które zastosujemy do instancji MaterialApp na górze hierarchii widżetów.

Dostosuj ThemeData.light()

Flutter ma kilka wbudowanych motywów. Jednym z nich jest jasny motyw. Zamiast tworzyć widżet ThemeData od podstaw, skopiujemy jasny motyw i zmienimy wartości, aby dostosować go do naszej aplikacji.

Zaimportujmy plik colors.dart w: app.dart.

import 'colors.dart';

Następnie dodaj do app.dart ten kod poza zakresem klasy ShrineApp:

// 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)
  );
}

Ustaw theme: na końcu funkcji build() w ShrineApp (w widżecie MaterialApp), aby ustawić go jako nasz nowy motyw:

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

Zapisz projekt. Twój ekran logowania powinien teraz wyglądać tak:

Android

iOS

strona logowania do świątyni o różowym i brązowym wystroju

strona logowania do świątyni o różowym i brązowym wystroju

5. Modyfikowanie typografii i stylów etykiet

Oprócz zmian kolorów projektant podał nam też typografię, której należy użyć. Flutter ThemeData zawiera 3 tematy tekstowe. Każdy motyw tekstu to kolekcja stylów tekstu, np. „nagłówek” i „tytuł”. Wykorzystamy kilka stylów aplikacji i zmienimy niektóre z nich.

Dostosowywanie motywu tekstowego

Aby zaimportować czcionki do projektu, należy je dodać do pliku pubspec.yaml.

W pliku pubspec.yaml bezpośrednio po tagu flutter: dodaj poniższy kod:

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

Masz już dostęp do czcionki Rubik i możesz jej używać.

Rozwiązywanie problemów z plikiem pubspec

Jeśli wytniesz i wkleisz powyższą deklarację, podczas uruchamiania polecenia pub get mogą wystąpić błędy. Jeśli pojawią się błędy, najpierw usuń początkowe odstępy i zastąp ją spacjami, stosując wcięcie dwukrotne. (Dwa spacje przed

fonts:

, cztery spacje przed

family: Rubik

).

Jeśli widzisz komunikat Mapowanie wartości jest niedozwolone, sprawdź wcięcie linii, której dotyczy problem, oraz wcięcie wierszy znajdujących się powyżej.

W usłudze login.dart zmień te elementy w elemencie Column():

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

W polu app.dart dodaj po _buildShrineTheme():

// 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,
      );
}

Spowoduje to zmianę motywu TextTheme i zmiany wyglądu nagłówków, tytułów i napisów.

Zastosowanie elementu fontFamily w ten sposób powoduje zastosowanie zmian tylko do wartości skali typograficznej określonych w zasadzie copyWith() (nagłówek, tytuł, podpis).

Dla niektórych czcionek ustawiamy niestandardową czcionkę, w przyrostach co 100: w500 (waga 500) odpowiada średniej, a w400 – zwykłej.

Użyj nowego tekstu motywy

Po błędzie dodaj do _buildShrineTheme te motywy:

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

Zapisz projekt. Tym razem uruchom też ponownie aplikację (Hot Restart), ponieważ zmodyfikowaliśmy czcionki.

Android

iOS

Strona siatki produktów w świątyni z zastosowanymi motywami tekstowymi

Tekst na ekranie logowania i ekranie głównym wygląda inaczej – w niektórych jest używana czcionka Rubika, a w innych – w kolorze brązowym, a nie czarnym lub białym. Ikony renderują się też w kolorze brązowym.

Zmniejszanie tekstu

Etykiety są za duże.

W funkcji home.dart zmień wartość children: w najbardziej wewnętrznej kolumnie:

// 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
],

Wyśrodkuj tekst i upuść go

Chcemy wyśrodkować etykiety i wyrównać tekst do dołu każdej karty zamiast do dołu każdego obrazu.

Przenieś etykiety na koniec (na dole) osi głównej i zmień je tak, by były wyśrodkowane:

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

Zapisz projekt.

Android

iOS

Strona siatki produktów w świątyni z różnym wyrównaniem tekstu

Strona siatki produktów w świątyni z różnym wyrównaniem tekstu

To znacznie lepiej.

Ustawianie motywu dla pól tekstowych

Możesz też określić motyw dekoracyjny w polach tekstowych, korzystając z elementu InputDecorationTheme.

W metodzie app.dart w metodzie _buildShrineTheme() określ wartość inputDecorationTheme::

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

Obecnie pola tekstowe mają ozdobę filled. Pozbądźmy się tego. Usunięcie elementu filled i określenie inputDecorationTheme spowoduje, że pola tekstowe otrzymają styl konturu.

W polu login.dart usuń wartości 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,
),

Ponowne uruchomienie z pamięci. Gdy pole Nazwa użytkownika jest aktywne (gdy wpisujesz tę nazwę), Twój ekran logowania powinien wyglądać tak:

Android

iOS

Strona logowania do świątyni z zaznaczonym polem nazwy użytkownika

Strona logowania do świątyni z zaznaczonym polem nazwy użytkownika

Wpisz tekst w polu tekstowym – ramki i pływające etykiety będą renderowane w kolorze podstawowym. Ale nie będzie to łatwe. Nie jest dostępna dla osób, które mają problem z rozróżnieniem pikseli o niewystarczającym kontraście kolorów. Więcej informacji znajdziesz w artykule o kolorach i ułatwieniach dostępu, które zawierają wytyczne dotyczące materiałów.

W polu app.dart podaj focusedBorder: w polu inputDecorationTheme: :

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

Następnie określ floatingLabelStyle: w polu inputDecorationTheme: :

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

Na koniec zadbajmy o zwiększenie kontrastu, dzięki czemu przycisk Anuluj będzie korzystał z koloru dodatkowego zamiast podstawowego.

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

Zapisz projekt.

Android

iOS

Strona logowania do świątyni z dostępnym przyciskiem ANULUJ

Strona logowania do świątyni z dostępnym przyciskiem ANULUJ

6. Dostosuj wysokość

Po określeniu stylu strony i określeniu koloru i typografii pasującej do świątyni świątyni dostosujmy wysokość.

Zmiana wysokości przycisku DALEJ

Domyślna wysokość dla: ElevatedButton to 2. Ustawmy go wyżej.

W login.dart dodaj wartość style: do elementu NEXT ElevatedButton:

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

Zapisz projekt.

Android

iOS

Strona logowania do świątyni z podwyższonym przyciskiem DALEJ

Strona logowania do świątyni z podwyższonym przyciskiem DALEJ

Dostosowywanie wysokości karty

W tej chwili karty leżą na białej powierzchni obok panelu nawigacyjnego strony.

W home.dart dodaj wartość elevation: do kart:

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

Zapisz projekt.

Android

iOS

Strona siatki produktów bez wysokości dla każdej karty

Strona siatki produktów bez wysokości dla każdej karty

Usunięto cień pod kartami.

7. Dodaj kształt

Świątynia ma styl geometryczny, który wyróżnia elementy na planie ośmiokąta lub prostokąta. Zaimplementujmy styl kształtu na kartach na ekranie głównym oraz w polach tekstowych i przyciskach na ekranie logowania.

Zmienianie kształtów pól tekstowych na ekranie logowania

W usłudze app.dart zaimportuj ten plik:

import 'supplemental/cut_corners_border.dart';

Będąc w aplikacji app.dart, zmień motyw dekoracji pól tekstowych, aby zastosować wycięte narożniki:

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

Zmiana kształtów przycisków na ekranie logowania

W usłudze login.dart dodaj ścięte prostokątne obramowanie do przycisku ANULUJ:

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)),
    ),
  ),
),

Przycisk TextButton nie ma widocznego kształtu, więc po co dodawać kształt obramowania? Animacja fali po dotknięciu jest więc powiązana z tym samym kształtem.

Teraz dodaj ten sam kształt do przycisku DALEJ:

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)),
    ),
  ),
),

Aby zmienić kształt wszystkich przycisków, możemy też użyć elementu elevatedButtonTheme lub textButtonTheme w elemencie app.dart. To nadal wyzwanie dla ucznia.

Ponowne uruchomienie z pamięci.

Android

iOS

Strona logowania do świątyni z zastosowaniem motywów kształtów

Strona logowania do świątyni z zastosowanymi motywami kształtów

8. Zmienianie układu

Następnie zmienimy układ, aby pokazać karty w różnych formatach obrazu i rozmiarze, aby każda z nich wyglądała inaczej niż inne.

Zastępowanie widoku GridView za pomocą funkcji AsymmetricView

Mamy już gotowe pliki do układu asymetrycznego.

W home.dart dodaj ten import:

import 'supplemental/asymmetric_view.dart';

Usuń _buildGridCards i zastąp body:

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

Zapisz projekt.

Android

iOS

Strona produktu świątyni z asymetrycznym układem z możliwością przewijania w poziomie

Strona produktu w świątyni z asymetrycznym układem z możliwością przewijania w poziomie

Teraz produkty przewijają się w poziomie, nawiązując do nich wzór.

9. Wypróbuj inny motyw (opcjonalnie)

Kolory to skuteczny sposób zaprezentowania marki, a niewielka zmiana koloru może mieć duży wpływ na wrażenia użytkownika. Aby to przetestować, zobaczmy, jak wygląda Shrine, jeśli jej kolorystyka nieco się różni.

Zmiana kolorów

W colors.dart dodaj ten kolor:

const kShrinePurple = Color(0xFF5D1049);

W app.dart zmień funkcję _buildShrineTheme() na:

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,
      ),
    ),
  );
}

Ponowne uruchomienie z pamięci. Nowy motyw powinien się pojawić.

Android

iOS

Strona logowania do świątyni z fioletowo-różowym motywem

Strona logowania do świątyni z fioletowo-różowym motywem

Android

iOS

Strona produktu związana ze świątynią z różowym motywem

Strona produktu związana ze świątynią z różowym motywem

Wynik jest zupełnie inny. Przywróćmy app.dart's _buildShrineTheme do stanu sprzed tego kroku. Możesz też pobrać kod startowy 104.

10. Gratulacje!

Masz już aplikację, która przypomina specyfikację projektowaną przez Twojego projektanta.

Dalsze kroki

Wiesz już, co to Material Flutter: motyw, typografia, wysokość i kształt. Więcej komponentów i podsystemów znajdziesz w bibliotece Material Flutter.

Przejrzyj pliki w katalogu supplemental i dowiedz się, jak opracowaliśmy siatkę z przewijaniem poziomym z asymetrycznym układem.

Co zrobić, jeśli planowany projekt aplikacji zawiera elementy, które nie mają komponentów w bibliotece? W filmie MDC-104: Material Advanced Komponenty pokazujemy, jak tworzyć komponenty niestandardowe za pomocą biblioteki Material Flutter, aby uzyskać odpowiedni wygląd.

Udało mi się ukończyć to ćwiczenia z programowania w rozsądny sposób i w rozsądny sposób

Całkowicie się zgadzam Zgadzam się Nie mam zdania Nie zgadzam się Całkowicie się nie zgadzam

Chcę w przyszłości nadal używać komponentów Material Komponenty

Całkowicie się zgadzam Zgadzam się Nie mam zdania Nie zgadzam się Całkowicie się nie zgadzam
.