1. Pengantar
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 material dan subsistem Flutter dalam codelab ini
- Panel aplikasi atas
- Petak
- Kartu
Bagaimana Anda menilai tingkat pengalaman Anda menggunakan pengembangan Flutter?
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
- Buka project di editor pilihan Anda.
- 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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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.