1. מבוא
Material Components (MDC) עוזר למפתחים להטמיע Material Design. MDC נוצר על ידי צוות של מהנדסים ומעצבי חוויית המשתמש ב-Google, שכולל עשרות רכיבים יפים ופונקציונליים של ממשק המשתמש. זמין ל-Android, ל-iOS, לאינטרנט ול-Flutter.material.io/develop |
עכשיו אפשר להשתמש ב-Material Flutter כדי להתאים אישית את האפליקציות סגנון ייחודי יותר מתמיד. ההתרחבות האחרונה של Material Design מאפשרת למעצבים ולמפתחים יותר גמישות להביע את המותג של המוצר שלהם.
ב-Codelabs MDC-101 ו-MDC-102 השתמשתם ב-Material Flutter כדי ליצור את היסודות של אפליקציה בשם Shrine, אפליקציית מסחר אלקטרוני למכירת בגדים ומוצרים לבית. האפליקציה הזו מכילה תהליך משתמש שמתחיל במסך התחברות, ולאחר מכן מעביר את המשתמשים למסך בית שמוצגים בו מוצרים.
מה תפַתחו
ב-Codelab הזה כדאי להתאים אישית את אפליקציית Shrine באמצעות:
- צבע
- טיפוגרפיה
- גובה
- צורה
- פריסה
Android | iOS |
רכיבים ומערכות משנה של Material Flutter ב-Codelab הזה
- עיצובים
- טיפוגרפיה
- גובה
- רשימת תמונות
איזה דירוג מגיע לדעתך לרמת הניסיון שלך בפיתוח Flutter?
2. הגדרת סביבת הפיתוח של Flutter
כדי להשלים את שיעור ה-Lab הזה אתם צריכים שתי תוכנות: Flutter SDK וכלי עריכה.
אפשר להריץ את Codelab באמצעות כל אחד מהמכשירים הבאים:
- מכשיר פיזי שמשמש ל-Android או ל-iOS שמחובר למחשב ומוגדר ל'מצב פיתוח'.
- הסימולטור של iOS (צריך להתקין כלים של Xcode).
- האמולטור של Android (נדרשת הגדרה ב-Android Studio).
- דפדפן (Chrome נדרש לניפוי באגים).
- בתור אפליקציית Windows , Linux או macOS למחשב. צריך לפתח בפלטפורמה שבה אתם מתכננים לפרוס. לכן, כדי לפתח אפליקציה למחשב של Windows, צריך לפתח את האפליקציה ב-Windows כדי לגשת לשרשרת ה-build המתאימה. יש דרישות ספציפיות למערכת ההפעלה שמפורטות בהרחבה בכתובת docs.flutter.dev/desktop.
3. הורדת האפליקציה לתחילת העבודה של Codelab
ממשיכים לעבור מ-MDC-102?
אם השלמתם את MDC-102, הקוד אמור להיות מוכן לשימוש ב-Codelab הזה. דלגו לשלב שינוי הצבעים.
מתחילים מאפס?
להורדת האפליקציה לתחילת פעולה של Codelab
האפליקציה לתחילת הפעולה נמצאת בספרייה material-components-flutter-codelabs-103-starter_and_102-complete/mdc_100_series
.
...או לשכפל אותו מ-GitHub
כדי לשכפל את ה-Codelab הזה מ-GitHub, מריצים את הפקודות הבאות:
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
פותחים את הפרויקט ומפעילים את האפליקציה
- פותחים את הפרויקט בכלי עריכה לבחירתכם.
- פועלים לפי ההוראות ל'הפעלת האפליקציה'. בקטע תחילת העבודה: נסיעת מבחן עבור העורך שנבחר.
הצלחת! אתם אמורים לראות במכשיר את דף ההתחברות ל-Shhine מ-Codelabs הקודמים.
Android | iOS |
לוחצים על 'הבא'. כדי לראות את דף המוצר.
Android | iOS |
4. שינוי הצבעים
נוצרה ערכת צבעים שמייצגת את המותג Shrine, והמעצב מעוניין להטמיע את ערכת הצבעים הזו באפליקציית Shrine
כדי להתחיל, נייבא את הצבעים האלה לפרויקט שלנו.
יצירה colors.dart
יצירת קובץ חצים חדש ב-lib
בשם colors.dart
. ייבוא של material.dart
והוספת הערכים 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;
לוח צבעים בהתאמה אישית
ערכת הצבעים הזו נוצרה על ידי מעצב עם צבעים מותאמים אישית (מוצגים בתמונה למטה). יש בו צבעים שנבחרו מהמותג של Shrine והוחלו על Material Theme Editor, שהרחיבה אותם ליצירת צבעים מלאים יותר. (הצבעים האלה לא נלקחו מלוחות הצבעים Material 2014).
הכלי Material Theme Editor ארגן אותם בגוונים לפי מספר, כולל תוויות 50, 100, 200, .... עד 900 מכל צבע. הגוון 50, 100 ו-300 מהדוגמית הוורודה ו-900 מהדוגמית החום משתמשים בגוונים בלבד.
כל פרמטר צבעוני של ווידג'ט ממופה לצבע מהערכות האלה. לדוגמה, הצבע של קישוטים לשדה טקסט בזמן שהוא מקבל קלט באופן פעיל צריך להיות הצבע הראשי של העיצוב. אם הצבע הזה לא נגיש (קל לראות אותו על הרקע שלו), השתמשו בצבע אחר במקום זאת.
עכשיו, אחרי ששמענו את הצבעים שאנחנו רוצים להשתמש בהם, אנחנו יכולים להחיל אותם על ממשק המשתמש. לשם כך נקבע את הערכים של ווידג'ט ThemeData שאנחנו מחילים על מופע ה-MaterialApp שנמצא בחלק העליון של היררכיית הווידג'טים שלנו.
התאמה אישית של ThemeData.light()
Flutter כוללת כמה עיצובים מובנים. העיצוב הבהיר הוא אחד מהם. במקום ליצור ווידג'ט של ThemeData מאפס, נעתיק את העיצוב הבהיר ונשנה את הערכים כדי להתאים אותם אישית לאפליקציה שלנו.
עכשיו נייבא את colors.dart
ב-app.dart.
import 'colors.dart';
לאחר מכן מוסיפים את הפקודה הבאה אל app.dart מחוץ להיקף המחלקה 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)
);
}
עכשיו, מגדירים את theme:
בסוף הפונקציה build()
של ShrineApp (בווידג'ט MaterialApp) כך שיהיה העיצוב החדש שלנו:
// TODO: Customize the theme (103)
theme: _kShrineTheme, // New code
שומרים את הפרויקט. עכשיו מסך ההתחברות אמור להיראות כך:
Android | iOS |
5. שינוי הסגנונות של הטיפוגרפיה והתוויות
מלבד השינויים בצבעים, המעצב נתן לנו גם טיפוגרפיה ספציפית לשימוש. ה-ThemeData של Flutter כולל 3 עיצובי טקסט. כל עיצוב של טקסט הוא אוסף של סגנונות טקסט, כמו "כותרת" ו-'title'. אנחנו נשתמש בכמה סגנונות לאפליקציה שלנו ונשנה חלק מהערכים.
התאמה אישית של עיצוב הטקסט
כדי לייבא גופנים לפרויקט, צריך להוסיף אותם לקובץ pubspec.yaml.
ב-pubspec.yaml, מוסיפים את הקוד הבא מיד אחרי התג flutter:
:
# TODO: Insert Fonts (103)
fonts:
- family: Rubik
fonts:
- asset: fonts/Rubik-Regular.ttf
- asset: fonts/Rubik-Medium.ttf
weight: 500
עכשיו אפשר לגשת לגופן Rubik ולהשתמש בו.
פתרון בעיות בקובץ ה-pubspec
אם תגזרו ותדביקו את ההצהרה שלמעלה, יכול להיות שיופיעו שגיאות בהרצה של pub get. אם מופיעות שגיאות, קודם כול מסירים את הרווח הלבן המוביל ומחליפים אותו ברווחים באמצעות כניסת פסקה עם 2 רווחים. (שני רווחים לפני
fonts:
, ארבעה רווחים לפני
family: Rubik
וכן הלאה.)
אם מופיעה ההודעה אסור להזין כאן ערכי מיפוי, צריך לבדוק את כניסת הפיסקה של השורה שבה קיימת הבעיה ואת כניסת הפיסקה של הקווים שמעליה.
ב-login.dart
, משנים את הפריטים הבאים בתוך Column()
:
Column(
children: <Widget>[
Image.asset('assets/diamond.png'),
const SizedBox(height: 16.0),
Text(
'SHRINE',
style: Theme.of(context).textTheme.headlineSmall,
),
],
)
ב-app.dart
, יש להוסיף את הערכים הבאים אחרי _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,
);
}
הפעולה הזו לוקחת TextTheme ומשנה את המראה של הכותרות, הכותרות והכתוביות.
החלה של fontFamily
באופן הזה מחילה את השינויים רק על ערכי סולם הטיפוגרפיה שצוינו ב-copyWith()
(כותרת, כותרת, כיתוב).
עבור גופנים מסוימים, אנחנו מגדירים גופן מותאם אישית במרווחים של 100: w500 (המשקל 500) תואם לבינוני ו-w400 תואם לערך רגיל.
השתמשו בטקסט החדשבנושאים
מוסיפים את העיצובים הבאים אל _buildShrineTheme
אחרי השגיאה:
// TODO: Add the text themes (103)
textTheme: _buildShrineTextTheme(base.textTheme),
textSelectionTheme: const TextSelectionThemeData(
selectionColor: kShrinePink100,
),
שומרים את הפרויקט. הפעם צריך גם להפעיל מחדש את האפליקציה (שנקראת הפעלה מחדש חמה), כי שינינו גופנים.
Android | iOS |
הטקסט במסכי ההתחברות ובמסכי הבית נראים אחרת. טקסט מסוים מופיע בגופן רוביק, וטקסטים אחרים מוצגים בצבע חום במקום בשחור או לבן. סמלים מופיעים גם בצבע חום.
כיווץ הטקסט
התוויות גדולות מדי.
בקובץ home.dart
, משנים את ה-children:
של העמודה הפנימית ביותר:
// 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
],
מרכוז הטקסט ומשחררים אותו
אנחנו רוצים למרכז את התוויות וליישר את הטקסט לתחתית של כל כרטיס, במקום לחלק התחתון של כל תמונה.
מעבירים את התוויות לסוף (התחתון) של הציר הראשי ומשנים אותן למרכז:
// TODO: Align labels to the bottom and center (103)
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
שומרים את הפרויקט.
Android | iOS |
זה נראה הרבה יותר טוב.
עיצוב שדות הטקסט
אפשר גם לעצב את העיצוב בשדות הטקסט באמצעות InputDecorationTheme.
ב-app.dart
, בשיטה _buildShrineTheme()
, מציינים ערך inputDecorationTheme:
:
// TODO: Decorate the inputs (103)
inputDecorationTheme: const InputDecorationTheme(
border: OutlineInputBorder(),
),
בשלב הזה, בשדות הטקסט מופיע קישוט מסוג filled
. נסיר את זה. אם מסירים את filled
ומציינים את inputDecorationTheme
, שדות הטקסט יהיו בסגנון המתאר.
ב-login.dart
, מסירים את הערכים של 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,
),
הפעלה מחדש מתוך הזיכרון. מסך ההתחברות אמור להיראות כך כשהשדה 'שם משתמש' פעיל (כשמקלידים אותו):
Android | iOS |
מקלידים בשדה טקסט – הגבולות והתוויות הצפות מוצגים בצבע הראשי. אבל קשה לנו לראות אותה. המצב הזה לא נגיש לאנשים שמתקשים להבדיל בין פיקסלים שאין בהם ניגודיות צבעים גבוהה מספיק. (למידע נוסף, עיינו במאמר על צבע ונגישות.)
ב-app.dart
, מציינים focusedBorder:
תחת inputDecorationTheme:
:
// TODO: Decorate the inputs (103)
inputDecorationTheme: const InputDecorationTheme(
border: OutlineInputBorder(),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 2.0,
color: kShrineBrown900,
),
),
),
בשלב הבא, מציינים floatingLabelStyle:
תחת inputDecorationTheme:
:
// TODO: Decorate the inputs (103)
inputDecorationTheme: const InputDecorationTheme(
border: OutlineInputBorder(),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
width: 2.0,
color: kShrineBrown900,
),
),
floatingLabelStyle: TextStyle(
color: kShrineBrown900,
),
),
לסיום, נאפשר שלחצן ביטול ישתמש בצבע המשני במקום בצבע הראשי להגברת הניגודיות.
TextButton(
child: const Text('CANCEL'),
onPressed: () {
_usernameController.clear();
_passwordController.clear();
},
style: TextButton.styleFrom(
primary: Theme.of(context).colorScheme.secondary,
),
),
שומרים את הפרויקט.
Android | iOS |
6. התאמת הגובה
עכשיו, לאחר שעיצבתם את הדף לצבע ולטיפוגרפיה ספציפיים שתואמים ל'מקדש', נתאים את הגובה.
שינוי הגובה של הלחצן 'הבא'
גובה ברירת המחדל של ElevatedButton
הוא 2. כדאי להעלות אותה למעלה.
ב-login.dart
, צריך להוסיף ערך של style:
ללחצן הגבוה הבא:
ElevatedButton(
child: const Text('NEXT'),
onPressed: () {
Navigator.pop(context);
},
style: ElevatedButton.styleFrom(
foregroundColor: kShrineBrown900,
backgroundColor: kShrinePink100,
elevation: 8.0,
),
),
שומרים את הפרויקט.
Android | iOS |
שינוי הגובה של הכרטיס
בשלב זה הכרטיסים מוצבים על משטח לבן לצד הניווט באתר.
ב-home.dart
, מוסיפים ערך של elevation:
לכרטיסים:
// TODO: Adjust card heights (103)
elevation: 0.0,
שומרים את הפרויקט.
Android | iOS |
הסרת את הצללית שמתחת לכרטיסים.
7. הוספת צורה
למקדש יש סגנון גיאומטרי מגניב שמגדיר אלמנטים עם צורה מתומן או מלבנית. עכשיו נטמיע את עיצוב הצורה הזה בכרטיסים במסך הבית ובשדות הטקסט ובלחצנים במסך ההתחברות.
שינוי הצורות של שדות הטקסט במסך ההתחברות
ב-app.dart
, מייבאים את הקובץ הבא:
import 'supplemental/cut_corners_border.dart';
עדיין ב-app.dart
, צריך לשנות את עיצוב העיצוב של שדות הטקסט כך שישתמשו בגבול של פינות חתוכות:
// TODO: Decorate the inputs (103)
inputDecorationTheme: const InputDecorationTheme(
border: CutCornersBorder(),
focusedBorder: CutCornersBorder(
borderSide: BorderSide(
width: 2.0,
color: kShrineBrown900,
),
),
floatingLabelStyle: TextStyle(
color: kShrineBrown900,
),
),
שינוי צורות הלחצנים במסך ההתחברות
ב-login.dart
, מוסיפים גבול מלבני משופע ללחצן ביטול:
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)),
),
),
),
ל'לחצן הטקסט' אין צורה נראית לעין, אז למה להוסיף צורה של גבול? כך, אנימציית הגלים מקושרת לאותה צורה כשנוגעים בה.
עכשיו מוסיפים את אותה הצורה ללחצן 'הבא':
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)),
),
),
),
כדי לשנות את הצורה של כל הלחצנים, אפשר להשתמש גם ב-elevatedButtonTheme
או ב-textButtonTheme
ב-app.dart
. זה נשאר כאתגר ללומדים!
הפעלה מחדש מתוך הזיכרון.
Android | iOS |
8. שינוי הפריסה
בשלב הבא נשנה את הפריסה כדי להציג כרטיסים ביחסי גובה-רוחב ובגדלים שונים, כך שכל כרטיס ייראה ייחודי מהאחרים.
החלפת GridView ב-AsymmetricView
כבר כתבנו את הקבצים לפריסה אסימטרית.
ב-home.dart
, מוסיפים את הייבוא הבא:
import 'supplemental/asymmetric_view.dart';
מוחקים את _buildGridCards
ומחליפים את השדה body
:
body: AsymmetricView(
products: ProductsRepository.loadProducts(Category.all),
),
שומרים את הפרויקט.
Android | iOS |
עכשיו המוצרים נגללים לרוחב בסגנון ארוג.
9. כדאי לנסות עיצוב אחר (אופציונלי)
צבע הוא דרך יעילה לבטא את המותג שלך, ושינוי קטן בצבע יכול להשפיע באופן משמעותי על חוויית המשתמש. כדי לבדוק את זה, בואו נראה איך 'מקדש' נראה אם העיצוב של המותג שונה מעט.
שינוי הצבעים
ב-colors.dart
, מוסיפים את הצבע הבא:
const kShrinePurple = Color(0xFF5D1049);
ב-app.dart
, משנים את הפונקציה _buildShrineTheme()
לאפשרות הבאה:
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,
),
),
);
}
הפעלה מחדש מתוך הזיכרון. העיצוב החדש אמור להופיע.
Android | iOS |
Android | iOS |
התוצאה שונה מאוד! נחזיר את _buildShrineTheme
של app.dart's
למה שהיה לפני השלב הזה. לחלופין, אפשר להוריד את קוד ההתחלה של קוד 104.
10. מעולה!
עד עכשיו יצרתם אפליקציה שדומה למפרטי העיצוב של המעצב שלכם.
השלבים הבאים
השתמשת עכשיו ב-Material Flutter: עיצוב, טיפוגרפיה, גובה וצורה. אפשר לחקור עוד רכיבים ומערכות משנה בספרייה Material Flutter.
אפשר לעיין בקבצים בספרייה supplemental
כדי לראות איך יצרנו את רשת הפריסה האסימטרית של הגלילה האופקית.
מה קורה אם עיצוב האפליקציה המתוכנן מכיל אלמנטים שאין להם רכיבים בספרייה? בקורס MDC-104: Material Advanced Components נסביר איך ליצור רכיבים מותאמים אישית באמצעות ספריית Material Flutter כדי להשיג מראה רצוי.