MDC-102 Flutter: Struktur dan Tata Letak Material

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

Dalam codelab MDC-101, Anda menggunakan dua Komponen Material untuk mem-build halaman login: tombol dan kolom teks dengan ink ripple (efek riak tinta). Sekarang, mari kita perluas dasar ini dengan menambahkan navigasi, struktur, dan data.

Yang akan Anda buat

Dalam codelab ini, Anda akan mem-build layar utama untuk aplikasi bernama Shrine, sebuah aplikasi e-commerce yang menjual pakaian dan perlengkapan rumah. Layar utama ini akan berisi:

  • Panel aplikasi atas
  • Daftar petak yang lengkap berisi produk

Android

iOS

aplikasi e-commerce dengan panel aplikasi atas dan petak yang penuh dengan produk

aplikasi e-commerce dengan panel aplikasi atas dan petak yang penuh dengan produk

Komponen material dan subsistem Flutter dalam codelab ini

  • Panel aplikasi atas
  • Petak
  • Kartu

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-101?

Jika Anda sudah menyelesaikan MDC-101, kode Anda untuk codelab ini seharusnya sudah disiapkan. Langsung ke langkah: Menambahkan panel aplikasi atas.

Memulai dari awal?

Mendownload aplikasi codelab awal

Aplikasi awal terletak di direktori material-components-flutter-codelabs-102-starter_and_101-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 102-starter_and_101-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 MDC-101 di perangkat Anda.

Android

iOS

halaman login dengan kolom nama pengguna dan sandi, tombol batal dan tombol berikutnya

halaman login dengan kolom nama pengguna dan sandi, tombol batal dan tombol berikutnya

Setelah layar login terlihat bagus, mari kita isi aplikasi dengan beberapa produk.

4. Menambahkan panel aplikasi atas

Saat ini, jika Anda mengklik tombol "Next", Anda akan dapat melihat layar utama yang bertuliskan "You did it!". Kerja bagus. Namun, sekarang pengguna tidak memiliki tindakan yang harus dilakukan atau tujuan mereka di aplikasi. Untuk membantu, kini saatnya menambahkan navigasi.

Desain Material menawarkan pola navigasi yang memastikan tingkat kegunaan yang tinggi. Salah satu komponen yang paling terlihat adalah panel aplikasi atas.

Untuk menyediakan navigasi serta memberi pengguna akses cepat ke tindakan lainnya, mari tambahkan panel aplikasi atas.

Menambahkan widget AppBar

Di home.dart, tambahkan AppBar ke Scaffold dan hapus const yang ditandai:

return const Scaffold(
  // TODO: Add app bar (102)
  appBar: AppBar(
    // TODO: Add buttons and title (102)
  ),

Menambahkan AppBar ke kolom appBar: Scaffold memberi kita tata letak yang sempurna secara gratis, dengan mempertahankan AppBar di bagian atas halaman dan isi di bawahnya.

Simpan project Anda. Saat aplikasi Shrine diupdate, klik Next untuk melihat layar utama.

Android

iOS

layar bertuliskan 'Anda berhasil!'

layar bertuliskan 'Anda berhasil!'

AppBar sudah terlihat bagus, tetapi Anda perlu menambahkan judul.

Menambahkan widget Text

Di home.dart, tambahkan judul ke AppBar:

// TODO: Add app bar (102)
  appBar: AppBar(
    // TODO: Add buttons and title (102)
    title: const Text('SHRINE'),
    // TODO: Add trailing buttons (102)

Simpan project Anda.

Android

iOS

panel aplikasi dengan Shrine sebagai judul

panel aplikasi dengan Shrine sebagai judul

Banyak panel aplikasi memiliki tombol di samping judul. Mari tambahkan ikon menu di aplikasi.

Menambahkan IconButton utama

Saat masih di home.dart, tetapkan IconButton untuk kolom leading: AppBar. (Tempatkan sebelum kolom title: untuk meniru urutan dari awal ke akhir):

    // TODO: Add buttons and title (102)
    leading: IconButton(
      icon: const Icon(
        Icons.menu,
        semanticLabel: 'menu',
      ),
      onPressed: () {
        print('Menu button');
      },
    ),

Simpan project Anda.

Android

iOS

panel aplikasi dengan Shrine sebagai judul dan ikon menu hamburger

panel aplikasi dengan Shrine sebagai judul dan ikon menu hamburger

Ikon menu (juga dikenal sebagai "hamburger") muncul tepat di tempat yang Anda harapkan.

Anda juga dapat menambahkan tombol ke sisi akhir judul. Di Flutter, ini disebut "actions".

Menambahkan tindakan

Terdapat ruang untuk dua IconButton lainnya.

Tambahkan ke instance AppBar setelah judul:

// TODO: Add trailing buttons (102)
actions: <Widget>[
  IconButton(
    icon: const Icon(
      Icons.search,
      semanticLabel: 'search',
    ),
    onPressed: () {
      print('Search button');
    },
  ),
  IconButton(
    icon: const Icon(
      Icons.tune,
      semanticLabel: 'filter',
    ),
    onPressed: () {
      print('Filter button');
    },
  ),
],

Simpan project Anda. Layar utama Anda akan terlihat seperti ini:

Android

iOS

panel aplikasi dengan Shrine sebagai judul dan ikon menu hamburger, serta penelusuran tambahan dan ikon kustom

panel aplikasi dengan Shrine sebagai judul dan ikon menu hamburger, serta penelusuran tambahan dan ikon kustom

Sekarang aplikasi memiliki tombol utama, judul, dan dua tindakan di sisi kanan. Panel aplikasi juga menampilkan ketinggian menggunakan bayangan halus yang menunjukkan bahwa panel aplikasi berada di lapisan yang berbeda dengan konten.

5. Menambahkan kartu dalam petak

Karena saat ini aplikasi ini memiliki beberapa struktur, mari kita susun konten dengan menempatkannya ke dalam kartu.

Menambahkan GridView

Mari mulai dengan menambahkan satu kartu di bawah panel aplikasi atas. Widget Kartu saja tidak memiliki cukup informasi untuk membuatnya muncul di tempat yang dapat dilihat, jadi kita sebaiknya mengenkapsulasi widget Kartu tersebut dalam widget GridView.

Ganti bagian tengah isi Scaffold dengan GridView:

// TODO: Add a grid view (102)
body: GridView.count(
  crossAxisCount: 2,
  padding: const EdgeInsets.all(16.0),
  childAspectRatio: 8.0 / 9.0,
  // TODO: Build a grid of cards (102)
  children: <Widget>[Card()],
),

Mari kita uraikan kode tersebut. GridView akan memanggil konstruktor count() karena jumlah item yang ditampilkannya dapat dihitung dan terbatas. Namun, diperlukan informasi lebih lanjut untuk menentukan tata letaknya.

crossAxisCount: menentukan banyaknya item. Kita ingin dua kolom.

Kolom padding: menyediakan ruang di keempat sisi GridView. Tentunya, Anda tidak dapat melihat padding di bagian akhir atau bawah karena belum ada turunan GridView di sebelahnya.

Kolom childAspectRatio: mengidentifikasi ukuran item berdasarkan rasio lebar tinggi (lebar dibagi tinggi).

Secara default, GridView membuat petak yang berukuran sama.

Kita memiliki satu kartu, tetapi kosong. Mari kita tambahkan widget turunan ke kartu.

Menata tata letak konten

Kartu harus memiliki region untuk gambar, judul, dan teks sekunder.

Update turunan GridView:

// TODO: Build a grid of cards (102)
children: <Widget>[
  Card(
    clipBehavior: Clip.antiAlias,
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: <Widget>[
        AspectRatio(
          aspectRatio: 18.0 / 11.0,
          child: Image.asset('assets/diamond.png'),
        ),
        Padding(
          padding: const EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Text('Title'),
              const SizedBox(height: 8.0),
              Text('Secondary Text'),
            ],
          ),
        ),
      ],
    ),
  )
],

Kode ini menambahkan widget Column yang digunakan untuk menata widget turunan secara vertikal.

crossAxisAlignment: field menentukan CrossAxisAlignment.start, yang berarti "meratakan teks ke tepi atas".

Widget AspectRasio menentukan bentuk gambar yang diambil, apa pun jenis gambar yang diberikan.

Padding menampilkan teks sedikit dari samping.

Kedua widget Text ditumpuk secara vertikal dengan delapan titik ruang kosong di antara keduanya (SizedBox). Kita membuat Column lagi untuk menyimpannya di dalam Padding.

Simpan project Anda.

Android

iOS

satu item dengan gambar, judul, dan teks sekunder

satu item dengan gambar, judul, dan teks sekunder

Dalam pratinjau ini, Anda dapat melihat kartu disisipkan dari tepi, dengan sudut bulat, dan bayangan (yang menunjukkan ketinggian kartu). Seluruh bentuk disebut "container" dalam Material. (Berbeda dengan class widget sebenarnya yang disebut Container.)

Kartu biasanya ditampilkan dalam koleksi dengan kartu lain. Mari kita susun sebagai koleksi dalam petak.

6. Membuat koleksi kartu

Setiap kali ada beberapa kartu di layar, kartu tersebut dikelompokkan ke dalam satu atau beberapa koleksi. Kartu dalam sebuah koleksi bersifat koplanar, yang berarti kartu berada pada ketinggian yang sama antara satu sama lain (kecuali kartu diambil atau ditarik, tetapi kita tidak akan melakukannya di sini).

Memperbanyak kartu agar menjadi sebuah koleksi

Saat ini, Kartu dibuat sebaris dengan kolom children: pada GridView. Itu adalah kode bertingkat yang sulit dibaca. Mari mengekstraknya menjadi fungsi yang dapat menghasilkan kartu kosong sebanyak yang kita inginkan, dan menampilkan daftar Kartu.

Buat fungsi pribadi baru di atas fungsi build() (ingat, fungsi yang dimulai dengan garis bawah adalah API pribadi):

// TODO: Make a collection of cards (102)
List<Card> _buildGridCards(int count) {
  List<Card> cards = List.generate(
    count,
    (int index) {
      return Card(
        clipBehavior: Clip.antiAlias,
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            AspectRatio(
              aspectRatio: 18.0 / 11.0,
              child: Image.asset('assets/diamond.png'),
            ),
            Padding(
              padding: const EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: const <Widget>[
                  Text('Title'),
                  SizedBox(height: 8.0),
                  Text('Secondary Text'),
                ],
              ),
            ),
          ],
        ),
      );
    },
  );
  return cards;
}

Tetapkan kartu yang dihasilkan ke kolom children GridView. Ingatlah untuk mengganti semua yang ada di GridView dengan kode baru ini:

// TODO: Add a grid view (102)
body: GridView.count(
  crossAxisCount: 2,
  padding: const EdgeInsets.all(16.0),
  childAspectRatio: 8.0 / 9.0,
  children: _buildGridCards(10) // Replace
),

Simpan project Anda.

Android

iOS

petak item dengan gambar, judul, dan teks sekunder

petak item dengan gambar, judul, dan teks sekunder

Kartu ada, tetapi belum menampilkan apa pun. Sekarang saatnya menambahkan data produk.

Menambahkan data produk

Aplikasi memiliki beberapa produk dengan gambar, nama, dan harga. Mari tambahkan ke widget yang sudah ada di kartu

Kemudian, di home.dart, impor paket baru dan beberapa file yang kita berikan untuk model data:

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';

import 'model/product.dart';
import 'model/products_repository.dart';

Terakhir, ubah _buildGridCards() untuk mengambil info produk, dan gunakan data tersebut dalam kartu:

// TODO: Make a collection of cards (102)

// Replace this entire method
List<Card> _buildGridCards(BuildContext context) {
  List<Product> products = ProductsRepository.loadProducts(Category.all);

  if (products.isEmpty) {
    return const <Card>[];
  }

  final ThemeData theme = Theme.of(context);
  final NumberFormat formatter = NumberFormat.simpleCurrency(
      locale: Localizations.localeOf(context).toString());

  return products.map((product) {
    return Card(
      clipBehavior: Clip.antiAlias,
      // TODO: Adjust card heights (103)
      child: Column(
        // TODO: Center items on the card (103)
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          AspectRatio(
            aspectRatio: 18 / 11,
            child: Image.asset(
              product.assetName,
              package: product.assetPackage,
             // TODO: Adjust the box size (102)
            ),
          ),
          Expanded(
            child: Padding(
              padding: const EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0),
              child: Column(
               // TODO: Align labels to the bottom and center (103)
               crossAxisAlignment: CrossAxisAlignment.start,
                // TODO: Change innermost Column (103)
                children: <Widget>[
                 // TODO: Handle overflowing labels (103)
                 Text(
                    product.name,
                    style: theme.textTheme.titleLarge,
                    maxLines: 1,
                  ),
                  const SizedBox(height: 8.0),
                  Text(
                    formatter.format(product.price),
                    style: theme.textTheme.titleSmall,
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }).toList();
}

CATATAN: Belum dapat dikompilasi dan dijalankan. Kita memiliki satu perubahan lagi.

Selain itu, ubah fungsi build() untuk meneruskan BuildContext ke _buildGridCards() sebelum Anda mencoba mengompilasinya:

// TODO: Add a grid view (102)
body: GridView.count(
  crossAxisCount: 2,
  padding: const EdgeInsets.all(16.0),
  childAspectRatio: 8.0 / 9.0,
  children: _buildGridCards(context) // Changed code
),

Mulai ulang aplikasi dengan cepat.

Android

iOS

petak item dengan gambar, judul produk, dan harga

petak item dengan gambar, judul produk, dan harga

Anda mungkin melihat bahwa ruang vertikal tidak ditambahkan di antara kartu. Itu karena kartu tersebut secara default memiliki margin 4 poin di bagian atas dan bawah.

Simpan project Anda.

Data produk muncul, tetapi gambar memiliki spasi tambahan di sekitarnya. Gambar dibuat dengan BoxFit .scaleDown secara default (dalam kasus ini). Mari kita ubah ke .fitWidth untuk sedikit memperbesar gambar dan menghapus spasi kosong tambahan.

Tambahkan kolom fit: ke gambar dengan nilai BoxFit.fitWidth:

  // TODO: Adjust the box size (102)
  fit: BoxFit.fitWidth,

Android

iOS

petak item dengan gambar, judul produk, dan harga yang dipangkas

petak item dengan gambar, judul produk, dan harga yang dipangkas

Produk ini kini tampil di aplikasi dengan sempurna.

7. Selamat!

Aplikasi ini memiliki alur dasar yang mengarahkan pengguna dari layar login ke layar utama, tempat produk dapat dilihat. Hanya dalam beberapa baris kode, panel aplikasi atas (dengan judul dan tiga tombol) serta kartu (untuk menampilkan konten aplikasi ini) ditambahkan. Layar utamanya kini sederhana dan fungsional, dengan struktur dasar dan konten yang dapat ditindaklanjuti.

Langkah berikutnya

Dengan panel aplikasi atas, kartu, kolom teks, dan tombol, kini kita telah menggunakan empat komponen inti dari library Material Flutter. Anda dapat mempelajari lebih lanjut dengan membuka Katalog widget komponen material.

Meskipun berfungsi sepenuhnya, aplikasi ini belum menyatakan merek atau sudut pandang tertentu. Dalam MDC-103: Memberi Tema Desain Material dengan Warna, Bentuk, Ketinggian, dan Jenis, kita akan menyesuaikan gaya komponen ini untuk mengekspresikan merek modern yang cerah.

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