MDC-102 Flutter: Tata Letak dan Struktur Material (Flutter)

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

Komponen MDC dalam codelab ini

  • Panel aplikasi atas
  • Petak
  • Kartu

Bagaimana Anda menilai tingkat pengalaman Anda menggunakan pengembangan Flutter?

Pemula Menengah Mahir

Sebelum memulai

Untuk mulai mengembangkan aplikasi seluler dengan Flutter, Anda harus:

  1. Mendownload dan menginstal Flutter SDK.
  2. Mengupdate PATH Anda dengan Flutter SDK.
  3. Menginstal Android Studio dengan plugin Flutter dan Dart, atau editor favorit Anda.
  4. Menginstal emulator Android, simulator iOS (memerlukan Mac dengan Xcode), atau menggunakan perangkat fisik.

Untuk informasi selengkapnya terkait penginstalan Flutter, lihat Get Started: Install. Untuk menyiapkan editor, lihat Get Started: Set up an editor. Saat menginstal emulator Android, Anda dapat menggunakan opsi default seperti ponsel Pixel 3 dengan Image Sistem terbaru. Tindakan ini direkomendasikan, tetapi tidak diperlukan untuk mengaktifkan akselerasi VM. Setelah menyelesaikan 4 langkah di atas, Anda dapat kembali ke codelab ini. Untuk menyelesaikan codelab ini, cukup instal Flutter untuk satu platform (Android atau iOS).

Memastikan Flutter SDK Anda berada dalam status yang tepat

Sebelum melanjutkan codelab ini, pastikan SDK Anda berada dalam status yang tepat. Jika Flutter SDK telah diinstal sebelumnya, gunakan flutter upgrade untuk memastikan bahwa SDK berada dalam status terbaru.

 flutter upgrade

flutter doctor. akan otomatis dijalankan saat Anda menjalankan flutter upgrade. Jika ini adalah penginstalan Flutter baru dan tidak memerlukan upgrade, jalankan flutter doctor secara manual. Anda akan menerima laporan jika ada dependensi yang harus diinstal untuk menyelesaikan penyiapan. Anda dapat mengabaikan tanda centang yang tidak relevan bagi Anda (misalnya, Xcode jika Anda tidak bermaksud untuk mengembangkan untuk iOS).

 flutter doctor

Pertanyaan Umum (FAQ)

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

Download aplikasi 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

Menyiapkan project

Petunjuk berikut menganggap Anda menggunakan Android Studio (IntelliJ).

Membuka project

1. Buka Android Studio.

2. Jika Anda melihat layar sambutan, klik Open an existing Android Studio project.

3 Buka direktori material-components-flutter-codelabs/mdc_100_series, lalu klik Open. Project akan terbuka. Anda dapat mengabaikan error yang muncul di Analisis Dart sampai Anda telah berhasil membuat project tersebut satu kali.

4. Jika diminta:

  • Instal update platform dan plugin apa pun, atau FlutterRunConfigurationType.
  • Jika Dart atau Flutter SDK tidak dikonfigurasi, tetapkan jalur Flutter SDK untuk plugin Flutter.
  • Konfigurasikan framework Android.
  • Klik "Get dependencies" atau "Run ‘flutter packages get'".

Lalu mulai ulang Android Studio.

Menjalankan aplikasi awal

Petunjuk berikut menganggap Anda melakukan pengujian di emulator atau perangkat Android, tetapi pengujian juga dapat dilakukan di Simulator atau perangkat iOS jika Anda telah menginstal Xcode.

1. Pilih perangkat atau emulator. Jika emulator Android belum dijalankan, pilih Tools -> Android -> AVD Manager untuk membuat perangkat virtual dan memulai emulator. Jika AVD sudah ada, Anda dapat memulai emulator langsung dari pemilih perangkat di Android Studio, seperti yang ditunjukkan di langkah berikutnya. (Untuk Simulator iOS, jika belum dijalankan, luncurkan simulatornya di mesin pengembangan Anda dengan memilih Flutter Device Selection -> Open iOS Simulator).

2. Mulai aplikasi Flutter Anda:

  • Cari menu drop-down Flutter Device Selection di bagian atas layar editor Anda, lalu pilih perangkatnya (misalnya, iPhone SE atau Android SDK yang dibuat untuk <versi>).
  • Tekan ikon Play ().

Berhasil! Anda akan melihat halaman login Shrine dari codelab MDC-101 di simulator atau emulator.

Android

iOS

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

Saat ini, jika Anda mengklik tombol "Next", Anda akan dapat melihat layar utama yang bertuliskan "You did it!". Kerja bagus. Namun, sekarang pengguna tidak dapat melakukan tindakan apa pun atau tidak tahu mereka di bagian aplikasi yang mana. Untuk membantu mengatasinya, kini saatnya Anda 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:

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

Dengan menambahkan AppBar ke kolom appBar: Scaffold, Anda dapat memberikan tata letak yang sempurna secara gratis, sehingga AppBar tetap berada di bagian atas halaman dan isi berada di bawahnya.

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

Android

iOS

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: Text('SHRINE'),
    // TODO: Add trailing buttons (102)

Simpan project.

Android

iOS

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: Icon(
        Icons.menu,
        semanticLabel: 'menu',
      ),
      onPressed: () {
        print('Menu button');
      },
    ),

Simpan project.

Android

iOS

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: Icon(
      Icons.search,
      semanticLabel: 'search',
    ),
    onPressed: () {
      print('Search button');
    },
  ),
  IconButton(
    icon: Icon(
      Icons.tune,
      semanticLabel: 'filter',
    ),
    onPressed: () {
      print('Filter button');
    },
  ),
],

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

Android

iOS

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.

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: 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 beberapa informasi untuk menentukan tata letak.

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.

Dengan menambahkan semuanya, GridView, akan menghitung setiap lebar turunan seperti berikut: ([width of the entire grid] - [left padding] - [right padding]) / number of columns. Menggunakan nilai yang kita miliki: ([width of the entire grid] - 16 - 16) / 2.

Tingginya dihitung dari lebar, dengan menerapkan rasio lebar tinggi: ([width of the entire grid] - 16 - 16) / 2 * 9 / 8. Angka 8 dan 9 dibalik karena kita memulai dengan lebar, lalu menghitung tinggi dan bukan sebaliknya.

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: EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: <Widget>[
              Text('Title'),
              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

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.

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) => 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: EdgeInsets.fromLTRB(16.0, 12.0, 16.0, 8.0),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <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: EdgeInsets.all(16.0),
  childAspectRatio: 8.0 / 9.0,
  children: _buildGridCards(10) // Replace
),

Simpan project:

Android

iOS

Kartu ada, tetapi belum menampilkan apa pun. Kini saatnya menambahkan beberapa 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/products_repository.dart';
import 'model/product.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 == null || 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: 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.headline6,
                    maxLines: 1,
                  ),
                  SizedBox(height: 8.0),
                  Text(
                    formatter.format(product.price),
                    style: theme.textTheme.subtitle2,
                  ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }).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: EdgeInsets.all(16.0),
  childAspectRatio: 8.0 / 9.0,
  children: _buildGridCards(context) // Changed code
),

Android

iOS

Anda mungkin melihat bahwa ruang vertikal tidak ditambahkan di antara kartu. Itu karena kartu, secara default, memiliki empat titik padding 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

Produk ini kini tampil di aplikasi dengan sempurna.

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 MDC-Flutter. Anda dapat menjelajahi lebih banyak komponen dengan mengunjungi Katalog Widget Flutter.

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.

Codelab berikutnya

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