1. Wprowadzenie
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 |
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?
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
- Otwórz projekt w wybranym edytorze.
- 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 |
Kliknij „Dalej” aby wyświetlić stronę produktu.
Android | iOS |
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.
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
Android | iOS |
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.