MDC-103 Flutter: Penerapan Tema Material dengan Warna, Bentuk, Ketinggian, dan Jenis

1. Pengantar

logo_components_color_2x_web_96dp.png

Komponen Material (MDC) membantu developer menerapkan Desain Material. Dibuat oleh tim engineer dan desainer UX di Google, MDC memiliki banyak komponen UI yang indah dan fungsional serta tersedia untuk Android, iOS, web, dan Flutter.material.io/develop

Kini Anda dapat menggunakan MDC untuk lebih menyesuaikan gaya unik aplikasi Anda. Ekspansi yang baru-baru ini dilakukan oleh Desain Material meningkatkan fleksibilitas desainer dan developer untuk mengekspresikan merek produk mereka.

Dalam codelab MDC-101 dan MDC-102, Anda menggunakan Komponen Material (MDC) untuk membangun dasar-dasar aplikasi bernama Shrine, sebuah aplikasi e-commerce yang menjual pakaian serta perlengkapan rumah. Aplikasi ini berisi alur penggunaan yang dimulai dengan layar login, kemudian mengarahkan pengguna ke layar utama yang menampilkan produk.

Yang akan Anda buat

Dalam codelab ini, Anda akan menyesuaikan aplikasi Shrine menggunakan:

  • Warna
  • Tipografi
  • Ketinggian
  • Bentuk
  • Tata Letak

Android

iOS

halaman login Shrine, bertema cokelat dan merah muda

halaman login Shrine, bertema cokelat dan merah muda

halaman produk Shrine, dengan panel aplikasi atas dan petak asimetris yang dapat di-scroll secara horizontal yang penuh dengan produk, bertema merah muda serta cokelat

halaman produk Shrine, dengan panel aplikasi atas dan petak asimetris yang dapat di-scroll secara horizontal yang penuh dengan produk, bertema merah muda serta cokelat

Komponen dan subsistem MDC-Flutter di codelab ini

  • Tema
  • Tipografi
  • Ketinggian
  • Daftar gambar

Bagaimana Anda menilai tingkat pengalaman Anda menggunakan pengembangan Flutter?

Pemula Menengah Mahir

2. Menyiapkan lingkungan pengembangan Flutter Anda

Anda memerlukan dua software untuk menyelesaikan lab ini—Flutter SDK dan editor.

Anda dapat menjalankan codelab menggunakan salah satu perangkat berikut:

  • Perangkat Android atau iOS fisik yang terhubung ke komputer dan disetel ke mode Developer.
  • Simulator iOS (perlu menginstal alat Xcode).
  • Android Emulator (memerlukan penyiapan di Android Studio).
  • Browser (Chrome diperlukan untuk proses debug).
  • Aplikasi desktop Windows, Linux, atau macOS. Anda harus melakukan pengembangan di platform tempat Anda berencana men-deploy aplikasi. Jadi, jika ingin mengembangkan aplikasi desktop Windows, Anda harus mengembangkannya di Windows untuk mengakses rantai build yang sesuai. Ada persyaratan spesifik per sistem operasi yang dibahas secara mendetail di docs.flutter.dev/desktop.

3. Mendownload aplikasi awal codelab

Melanjutkan dari MDC-102?

Jika Anda sudah menyelesaikan MDC-102, kode Anda seharusnya siap untuk codelab ini. Lewati ke langkah: Mengubah warna.

Memulai dari awal?

Mendownload aplikasi codelab awal

Aplikasi awal terletak di direktori material-components-flutter-codelabs-103-starter_and_102-complete/mdc_100_series.

...atau meng-clone codelab dari GitHub

Untuk meng-clone codelab ini dari GitHub, jalankan perintah berikut:

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

Membuka project dan menjalankan aplikasi

  1. Buka project di editor pilihan Anda.
  2. Ikuti petunjuk untuk "Run the app" (Jalankan aplikasi) di Get Started: Test drive pada editor pilihan Anda.

Berhasil! Anda akan melihat halaman login Shrine dari codelab sebelumnya di perangkat Anda.

Android

iOS

halaman login Shrine tidak bertema

halaman login Shrine tidak bertema

Klik "Next" untuk melihat halaman beranda dari codelab sebelumnya.

Android

iOS

halaman petak produk Shrine tidak bertema

halaman petak produk Shrine tidak bertema

4. Mengubah warna

Skema warna yang merepresentasikan merek Shrine telah dibuat, dan desainer ingin Anda mengimplementasikan skema warna tersebut ke aplikasi Shrine

Untuk memulai, mari kita impor warna tersebut ke project kita.

Membuat colors.dart

Buat file dart baru di lib bernama colors.dart. Impor Komponen Material dan tambahkan nilai 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;

Palet warna kustom

Tema warna ini telah dibuat oleh desainer dengan warna kustom (ditampilkan di gambar di bawah). Tema warna ini berisi warna yang telah dipilih dari merek Shrine dan diterapkan ke Material Theme Editor, yang telah memperluasnya untuk membuat palet yang lebih lengkap. (Warna ini bukan dari palet warna Material 2014.)

Material Theme Editor telah mengatur warna-warna tersebut menjadi shade yang diberi label secara numerik, meliputi label 50, 100, 200, .... hingga 900 untuk setiap warna. Shrine hanya menggunakan shade 50, 100, dan 300 dari swatch merah muda dan 900 dari swatch cokelat.

b9170eb94fd3b106.jpeg f8b4b97f898f154e.png

Setiap parameter widget berwarna dipetakan ke warna dari skema ini. Misalnya, warna untuk dekorasi kolom teks ketika menerima input secara aktif harus berupa Warna primer tema. Jika warna tersebut tidak dapat diakses (mudah dilihat pada latar belakangnya), gunakan PrimaryVariant sebagai gantinya.

Variasi ini dibuat untuk Pedoman Material 2014 dan masih tersedia di pedoman (artikel Color System ) dan MDC-Flutter saat ini. Untuk mengaksesnya dalam kode, cukup panggil warna dasar kemudian shade-nya (umumnya nilai ratusan). Misalnya, Merah Muda 400 diambil dengan perintah: Colors.pink[400].

Anda dapat menggunakan palet ini untuk desain dan kode Anda. Jika sudah memiliki warna yang spesifik untuk merek Anda, Anda dapat membuat palet harmonis Anda sendiri menggunakan alat pembuatan palet atau Material Theme Editor.

Setelah memiliki warna yang ingin digunakan, kita dapat menerapkannya ke UI. Kita akan melakukan ini dengan menyetel nilai widget ThemeData yang kita terapkan ke instance MaterialApp di bagian atas hierarki widget kita.

Menyesuaikan ThemeData.light()

Flutter menyertakan beberapa tema bawaan. Salah satunya adalah tema terang. Kita akan menyalin tema terang dan mengubah nilainya agar sesuai untuk aplikasi kita, bukan membuat widget ThemeData dari awal.

Mari kita impor colors.dart di app.dart.

import 'colors.dart';

Kemudian, tambahkan hal berikut ke app.dart di luar cakupan class ShrineApp:

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

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

Sekarang, tetapkan theme: di bagian akhir fungsi build() ShrineApp (di widget MaterialApp) agar menjadi tema baru kita:

  // TODO: Add a theme (103)
  theme: _kShrineTheme, // New code

Simpan project Anda. Layar login Anda sekarang akan terlihat seperti ini:

Android

iOS

halaman login Shrine bertema merah muda dan cokelat

halaman login Shrine bertema merah muda dan cokelat

Dan layar utama Anda akan terlihat seperti ini:

Android

iOS

halaman petak produk Shrine bertema merah muda dan cokelat

halaman petak produk Shrine bertema merah muda dan cokelat

5. Mengubah gaya label dan tipografi

Selain perubahan warna, desainer juga telah memberi kita tipografi spesifik untuk digunakan. ThemeData Flutter mencakup 3 tema teks. Setiap tema teks adalah koleksi gaya teks, seperti "headline" dan "title". Kita akan menggunakan beberapa gaya untuk aplikasi kita dan mengubah beberapa nilainya.

Menyesuaikan tema teks

Untuk mengimpor font ke project, font harus ditambahkan ke file pubspec.yaml.

Di pubspec.yaml, tambahkan kode berikut langsung setelah tag flutter::

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

Sekarang Anda dapat mengakses dan menggunakan font Rubik.

Memecahkan masalah file pubspec

Anda mungkin mengalami error saat menjalankan pub get jika Anda memotong dan menempel deklarasi di atas. Jika Anda mengalami error, mulai dengan menghapus spasi kosong di awal dan menggantinya dengan indentasi 2 spasi. (Dua spasi sebelumnya

fonts:

, empat spasi sebelumnya

family: Rubik

, dan seterusnya.)

Jika Anda melihat Mapping values are not allowed here, periksa indentasi baris yang memiliki masalah dan indentasi baris di atasnya.

Di login.dart, ubah kode berikut di dalam Column():

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

Di app.dart, tambahkan kode berikut setelah _buildShrineTheme():

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

Tindakan ini mengambil TextTheme dan mengubah tampilan headline, judul, dan teks.

Menerapkan fontFamily dengan cara ini akan menerapkan perubahan hanya ke nilai skala tipografi yang ditentukan di copyWith() (judul utama, judul, teks).

Untuk beberapa font, kita menyetel fontWeight kustom dalam kelipatan 100: w500 (ketebalan 500) sesuai dengan medium dan w400 sesuai dengan reguler.

Menggunakan tema teks baru

Tambahkan tema berikut ke _buildShrineTheme setelah error:

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

Simpan project Anda. Kali ini, mulai ulang juga aplikasi (dikenal sebagai Hot Restart), karena kita mengubah font.

Android

iOS

halaman petak produk Shrine dengan tema teks diterapkan

halaman petak produk Shrine dengan tema teks diterapkan

Teks di layar utama dan layar login terlihat berbeda—beberapa teks menggunakan font Rubik, dan teks lainnya dirender dengan warna cokelat, bukan hitam atau putih. Ikon juga dirender dengan warna cokelat.

Menyusutkan teks

Labelnya sedikit terlalu besar.

Di home.dart, ubah children: dari Column terdalam:

// 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.caption,
  ),
  // End new code
],

Menempatkan teks di tengah bawah

Kita ingin menempatkan label di tengah, dan meratakan teks ke bagian bawah setiap kartu, bukan ke bagian bawah setiap gambar.

Pindahkan label ke akhir (bawah) sumbu utama dan ubah ke posisi tengah:

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

Simpan project Anda.

Android

iOS

halaman petak produk Shrine dengan perataan teks berbeda

halaman petak produk Shrine dengan perataan teks berbeda

Ubahan ini membuat halaman terlihat jauh lebih baik.

Memberi tema kolom teks

Anda juga dapat memberi tema dekorasi di kolom teks dengan InputDecorationTheme.

Di app.dart, di metode _buildShrineTheme(), tentukan nilai inputDecorationTheme::

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

Saat ini, kolom teks memiliki dekorasi filled. Mari kita hapus. Menghapus filled dan menentukan inputDecorationTheme akan memberikan gaya garis batas untuk kolom teks.

Di login.dart, hapus nilai 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,
),

Hot restart. Layar login Anda akan terlihat seperti ini ketika kolom Username aktif (saat Anda mengetik di kolom tersebut):

Android

iOS

halaman login Shrine dengan fokus pada kolom Username

halaman login Shrine dengan fokus pada kolom Username

Ketik di dalam kolom teks—batas dan label mengambang akan dirender dengan warna primer. Tetapi kita tidak dapat melihatnya dengan mudah. Teks tersebut tidak dapat diakses bagi orang yang kesulitan membedakan piksel dan tidak memiliki kontras warna yang cukup. (Untuk mengetahui informasi selengkapnya, lihat "Warna yang tersedia" di artikel tentang Warna Pedoman Material.)

Di app.dart, tentukan focusedBorder: di bawah inputDecorationTheme: :

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

Selanjutnya, tentukan floatingLabelStyle: di bawah inputDecorationTheme: :

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

Terakhir, gunakan warna sekunder, bukan warna primer, pada tombol Cancel untuk meningkatkan kontras.

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

Simpan project Anda.

Android

iOS

halaman login Shrine dengan tombol CANCEL yang dapat diakses

halaman login Shrine dengan tombol CANCEL yang dapat diakses

6. Menyesuaikan ketinggian

Setelah Anda memberikan gaya pada halaman dengan warna dan tipografi spesifik yang cocok dengan Shrine, mari kita sesuaikan ketinggian.

Mengubah ketinggian tombol NEXT

Ketinggian default untuk ElevatedButton adalah 2. Mari kita naikkan lebih tinggi.

Di login.dart, tambahkan nilai style: ke ElevatedButton NEXT:

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

Simpan project Anda.

Menyesuaikan ketinggian Kartu

Saat ini, kartu diletakkan di atas permukaan putih di samping navigasi situs.

Di home.dart, tambahkan nilai elevation: ke Kartu:

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

Simpan project.

Android

iOS

halaman petak produk Shrine tanpa ketinggian untuk setiap kartu

halaman petak produk Shrine tanpa ketinggian untuk setiap kartu

Anda telah menghapus bayangan di bawah kartu.

7. Menambahkan Bentuk

Shrine memiliki gaya geometrik yang keren, yang menentukan elemen dengan bentuk persegi delapan atau persegi panjang. Mari kita terapkan pemberian gaya pada bentuk pada kartu di layar utama, serta kolom serta tombol teks di layar login.

Mengubah bentuk kolom teks di layar login

Di app.dart, impor file berikut:

import 'supplemental/cut_corners_border.dart';

Masih di app.dart, ubah tema dekorasi kolom teks untuk menggunakan batas sudut yang dipotong:

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

Mengubah bentuk tombol di layar login

Di login.dart, tambahkan batas persegi panjang yang miring ke tombol CANCEL:

TextButton(
  child: const Text('CANCEL'),
  onPressed: () {
    _usernameController.clear();
    _passwordController.clear();
  },
  style: TextButton.styleFrom(
    primary: Theme.of(context).colorScheme.secondary,
    shape: const BeveledRectangleBorder(
      borderRadius: BorderRadius.all(Radius.circular(7.0)),
    ),
  ),
),

TextButton tidak memiliki bentuk yang terlihat, jadi mengapa kita menambahkan bentuk batas? Agar animasi ripple terikat dengan bentuk yang sama saat disentuh.

Sekarang tambahkan bentuk yang sama ke tombol NEXT:

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

Untuk mengubah bentuk semua tombol, kita juga dapat menggunakan elevatedButtonTheme atau textButtonTheme di app.dart. Ini merupakan tantangan bagi orang yang mempelajarinya.

Hot restart.

Android

iOS

halaman login Shrine dengan tema bentuk diterapkan

halaman login Shrine dengan tema bentuk diterapkan

8. Mengubah tata letak

Selanjutnya, mari kita ubah tata letak untuk menampilkan kartu dalam ukuran dan rasio aspek yang berbeda, sehingga setiap kartu terlihat unik dari kartu lain.

Mengganti GridView dengan AsymmetricView

Kita sudah menulis file untuk tata letak asimetris.

Di home.dart, tambahkan impor berikut:

import 'supplemental/asymmetric_view.dart';

Hapus _buildGridCards dan ganti dengan body:

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

Simpan project.

Android

iOS

halaman produk Shrine dengan tata letak asimetris yang dapat di-scroll secara horizontal

halaman produk Shrine dengan tata letak asimetris yang dapat di-scroll secara horizontal

Sekarang produk di-scroll secara horizontal dalam pola seperti anyaman.

9. Mencoba tema yang lain (Opsional)

Warna adalah cara efektif untuk mengekspresikan merek Anda, dan perubahan kecil pada warna dapat berpengaruh besar pada pengalaman pengguna Anda. Untuk mengujinya, mari kita lihat tampilan Shrine jika skema warna mereknya sedikit berbeda.

Mengubah warna

Di colors.dart, tambahkan warna berikut:

const kShrinePurple = Color(0xFF5D1049);

Di app.dart, ubah fungsi _buildShrineTheme() menjadi:

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,
    ),
    inputDecorationTheme: const InputDecorationTheme(
      border: CutCornersBorder(),
      focusedBorder: CutCornersBorder(
        borderSide: BorderSide(
          width: 2.0,
          color: kShrinePurple,
        ),
      ),
      floatingLabelStyle: TextStyle(
        color: kShrinePurple,
      ),
    ),
  );
}

Hot restart. Sekarang, tema baru akan muncul.

Android

iOS

halaman login Shrine dengan tema ungu dan putih

halaman login Shrine dengan tema ungu dan putih

Android

iOS

halaman produk Shrine dengan tema ungu dan putih

halaman produk Shrine dengan tema ungu dan putih

Hasilnya sangatlah berbeda. Mari kita ubah kembali _buildShrineTheme di app.dart's menjadi seperti semula. Atau, download kode awal untuk 104.

10. Selamat!

Sekarang, Anda telah membuat aplikasi yang menyerupai spesifikasi desain dari desainer Anda.

Langkah berikutnya

Sekarang Anda telah menggunakan komponen MDC berikut: tema, tipografi, ketinggian, dan bentuk. Anda dapat mempelajari lebih banyak komponen dan subsistem di library MDC-Flutter.

Temukan file-file di direktori supplemental untuk mempelajari cara kita membuat scroll horizontal, petak tata letak asimetris.

Bagaimana jika desain rencana aplikasi Anda berisi elemen yang tidak memiliki komponen di library MDC? Di MDC-104: Komponen Lanjutan Desain Material, kami menunjukkan cara membuat komponen kustom menggunakan library MDC untuk mencapai tampilan yang spesifik.

Saya dapat menyelesaikan codelab ini dengan upaya dan dalam durasi waktu yang wajar

Sangat setuju Setuju Netral Tidak setuju Sangat tidak setuju

Saya ingin terus menggunakan Komponen Material pada masa mendatang

Sangat setuju Setuju Netral Tidak setuju Sangat tidak setuju