Terakhir diperbarui: 24 September 2023
Penulis: Habibie Ed Dien
Pada codelab ini, Anda akan mempelajari konsep dan praktik untuk dasar-dasar framework Flutter termasuk fitur penggunaan hot reload dan restart serta widget dasar dan temanya.
Setelah menyelesaikan codelab ini Anda akan mampu untuk:
Berikut merupakan sumber daya yang diperlukan untuk menyelesaikan praktikum ini:
Ketika membuat project flutter secara default berikut adalah struktur folder dan filenya. Dapat kita lihat strukturnya terdiri dari .dart_tool, .idea, android, ios, lib, test, .gitignore, .metadata, .packages, .flutter_basic.iml, pubspec.lock, pubspec.yaml, README.md.
Berikut adalah penjelasan yang lebih detail tentang struktur files dari flutter.
project yang degenerate sesuai dengan file pubspec.yaml
.
pengembangan aplikasi.
Untuk struktur folder akan dijelaskan pada bagian berikut.
Perhatikan pada folder project flutter terdapat dua folder yaitu folder ios dan folder android, dengan menggunakan kedua folder tersebut flutter dapat membuat aplikasi berbasis ios dan berbasis android dalam satu project.
Folder android berisi file-file pendukung untuk mengenerate project android dan akan dikompilasi menjadi sebuah apk pada folder build. Namun anda jarang atau bahkan tidak perlu mengedit yang ada di folder android. Anda akan banyak bekerja di folder lib.
Berisi project ios, folder ini sama dengan folder android, sangat jarang dan bahkan tidak perlu untuk mengubah apapun pada folder ios. Folder ios dan android dikelola oleh flutter sdk yang akan dimerge (disatukan) dengan code yang ada di folder lib untuk membuat aplikasi ios dan android.
Folder lib berisi kode program dengan bahasa dart yang berupa widget yang dapat dibuat sesuai dengan kebutuhan aplikasi anda.
Berisi source code dart yang digunakan untuk melakukan test secara otomatis pada aplikasi flutter.
Pada file ini berisi konfigurasi konfigurasi project flutter yang dibuat dimana anda dapat mendata asset berupa font, gambar dan lain lain. Pada file ini anda juga dapat mengkonfigurasi flutter sdk dan konfigurasi yang terkait flutter.
Pada flutter terdapat fungsi hot reload dan hot restart yang digunakan untuk pengembangan aplikasi dengan flutter. Hot reload mencompile source code yang baru ditambahkan dan dikirimkan ke dart virtual machine lalu diupdate. Setelah selesai update, dart virtual machine akan memperbarui UI sesuai dengan perubahan. Keunggulan hot reload adalah waktu prosenya yang cepat dibanding hot restart. Akan tetapi hot reload mempertahankan state yang ada sehingga jika menggunakan state maka nilai dari widget tidak akan berubah.
Hot restart akan meng-compile ulang aplikasi dan mereset (destroy) state yang ada. Jadi hot restart akan mem-build ulang widget tree sesuai dengan code yang telah diperbarui.
Berikut ini penjelasan terkait project flutter yang nanti akan Anda praktikkan pada Praktikum 1.
Seperti halnya kode program pada umumnya dart dapat menggunakan statement import untuk mengimport package, library, atau file lain yang digunakan pada file yang dieksekusi.
import 'package:flutter/material.dart';
Main function pada flutter dibuat dengan menggunakan kode program berikut ini dimana semua proses aplikasi dimulai dari mengeksekusi fungsi main.
void main() {
runApp(MyApp());
}
Perhatikan pada fungsi main ini yang di eksekusi adalah class MyApp dimana class MyApp harus mengextend salah satu StatlessWidget atau StatefullWidget, ingat bahwa flutter membangun UI menggunakan widget.
Flutter menggunakan Widget sebagai elemen-elemen pembangun UI, widget ini adalah kode program yang diterjemahkan menjadi tampilan yang dapat dilihat dan diinteraksikan oleh pengguna. Stateless widget bersifat statis / final dimana nilai atau konfigurasi telah diinisiasi sejak awal, nilai variabel pada widget ini tidak dapat diubah oleh widget ini sendiri tetapi dapat diubah oleh parent widget nya jika parent nya adalah StatefullWidget. Struktur dasar stateless widget adalah sebagai berikut:
class exampleStateless extends StatelessWidget{
@override
Widget build(BuildContext context) {
}
}
Stateful widget bersifat dinamis, widget ini dapat diperbarui ketika dibutuhkan sesuai dengan action pengguna atau jika ada ada perubahan data. Perubahan data pada stateful widget di trigger oleh perubahan state, oleh karena itu sebuah StatefulWidget selalu memiliki State. Struktur dasar stateful widget adalah sebagai berikut:
class exampleStateless extends StatefulWidget{
@override
State<StatefulWidget> createState() {
}
}
Widget memiliki peranan sangat penting dalam Pengembangan aplikasi Flutter. Widget adalah bagian yang membentuk UI; kodenya merupakan representasi dari apa yang terlihat oleh pengguna.
UI hampir tidak pernah bersifat statis; mereka sering berubah, seperti yang akan Anda alami ketika Anda menggunakan halaman web atau aplikasi. Meskipun tidak dapat diubah menurut definisi, widget tidak dimaksudkan untuk menjadi final – lagi pula, kita berurusan dengan UI, dan UI pasti akan berubah selama siklus hidup aplikasi apa pun. Itu sebabnya Flutter menyediakan dua jenis widget: stateless dan stateful.
Immutability
Sebagian besar bahasa pemrograman merujuk pada istilah "immutable". Object Immutable adalah objek yang tidak pernah berubah. Artinya, itu tidak dapat mengubah dirinya sendiri, dan itu tidak dapat diubah secara eksternal. Sebaliknya, jika perubahan diperlukan, maka objeknya adalah diganti begitu saja. Stateless Widget immutable karena tidak dapat mengubah properties atau state, sesuatu yang eksternal juga tidak dapat mengubah properties atau statenya. Jika widget perlu diubah, maka secara efektif diganti dengan widget baru yang memiliki properties atau state yang berbeda.
Seperti yang Anda duga, widget stateless tidak memiliki state, sedangkan widget stateful memiliki state dan beradaptasi berdasarkan state itu. Perbedaan ini berdampak pada life cycle widget, bagaimana kode dibangun, dan disusun. Kewajiban developer untuk memilih jenis widget apa yang digunakan dalam setiap situasi. Secara umum, seorang developer harus menggunakan stateless sebagai opsi default kecuali widget yang perlu menggunakan state. Stateful widget yang dapat digunakan untuk setiap skenario, tetapi ini akan memengaruhi kinerja dan pemeliharaan kode.
Selain itu, Flutter menggunakan konsep widget yang diwarisi (tipe InheritedWidget), yang juga merupakan sejenis widget, tetapi sedikit berbeda dari dua jenis lainnya yang telah dijelaskan.
Stateless widgets
Sebuah typical UI akan terdiri dari banyak widget, dan beberapa di antaranya tidak akan pernah mengubah propertinya setelah dipakai. Mereka tidak memiliki state; yaitu, mereka tidak berubah dengan sendirinya melalui tindakan atau perilaku internal. Sebaliknya, mereka diubah oleh eksternal event pada parent widget di widget tree. Jadi, aman untuk mengatakan bahwa widget stateless memberikan kontrol tentang bagaimana mereka dibangun menuju parent widget di tree. Diagram berikut menunjukkan representasi dari widget stateless:
Dalam diagram diatas, parent widget membuat instance child stateless widget dan meneruskan sekumpulan properti selama pembuatan instance. Child widget hanya dapat menerima properti ini dari parent widget dan tidak akan mengubah dengan sendirinya. Dalam hal kode, ini berarti bahwa widget stateless hanya memiliki properti akhir yang ditentukan selama construction, dan properti ini hanya dapat diubah melalui pembaruan parent widget dengan perubahan kemudian meneruskan menuju child widget.
Mari kita lihat contoh stateless widget dari Hello World! aplikasi yang kita jelajahi di bab-bab sebelumnya.
Contoh Kode Program
Stateless widget pertama di dalam aplikasi adalah kelas aplikasi itu sendiri:
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
Seperti yang Anda lihat, class MyApp extends StatelessWidget
dan overrides metode build(BuildContext
). Metode build sangat penting untuk semua widget dan menjelaskan bagaimana widget akan muncul di layar. Ini dilakukan dengan membangun subtree widget di bawahnya. MyApp
merupakan root dari widget tree; itu adalah widget top-level yang dipakai dalam metode runApp
dalam metode main
Dart. Oleh karena itu, ia membangun semua widget di bawah tree. Dalam contoh ini, turunan langsungnya adalah MaterialApp
. Menurut dokumentasi, MaterialApp
dapat didefinisikan sebagai berikut:
"A convenience widget that wraps a number of widgets that are commonly required for material design applications."
Material Design
Material Design adalah kumpulan desain dan pengalaman digital standar yang dibuat oleh Google untuk membantu tim membangun UI berkualitas tinggi. Apple memiliki padanan bernama Cupertino, dan kita akan melihat contoh keduanya pada materi ini.
Dalam contoh ini, stateless widget tidak menerima properti apa pun dari parent karena tidak memiliki parent. Kami akan melihat contoh properti yang diteruskan nanti.
BuildContext
adalah argumen yang disediakan untuk metode build
sebagai cara yang berguna untuk berinteraksi dengan widget tree. Ini memungkinkan Anda untuk mengakses informasi ancestral penting yang membantu menggambarkan widget yang sedang dibangun. Misalnya, data tema yang ditentukan dalam widget ini dapat diakses oleh semua child widget untuk memastikan ada tampilan dan nuansa yang konsisten pada aplikasi Anda.
Selain properti lainnya, MaterialApp
berisi properti home. Ini adalah widget pertama yang ditampilkan dalam aplikasi Anda. Di sini, home
mengacu pada widget MyHomePage
, yang bukan merupakan widget bawaan, melainkan widget stateful yang didefinisikan dalam Aplikasi Hello World!.
Anda sekarang seharusnya dapat memahami bagaimana Flutter menyusun widget untuk membuat tampilan. Mari kita lihat partner widget stateless, yaitu widget stateful.
Tidak seperti widget stateless, yang menerima properti dari induknya (parent) yang konstan sepanjang masa pakai widget, widget stateful dimaksudkan untuk mengubah propertinya secara dinamis selama masa pakainya. Menurut definisi, widget stateful juga tidak dapat diubah, tetapi mereka memiliki kelas State pendamping yang mewakili state widget saat ini. Ini ditunjukkan dalam diagram berikut:
Dalam diagram diatas, widget membuat instance child widget dan, mirip dengan contoh widget stateless, meneruskan properti ke child. Properti ini, sekali lagi, final dan tidak dapat diubah di dalam widget. Namun, tidak seperti contoh widget stateless, objek State pendamping juga memiliki akses ke properti widget dan, selain itu, mampu menampung properti lain yang tidak final.
Dengan menahan state widget di objek separate State, framework dapat merebuild widget kapan pun diperlukan tanpa kehilangan state terkait saat ini. Elemen pada tree elemen menyimpan referensi ke widget yang sesuai dan juga objek State yang terkait dengannya. Objek State akan memberi tahu Anda ketika widget perlu dibangun kembali dan kemudian melakukan pembaruan di elemen tree juga.
Contoh Kode Program
MyHomePage
adalah widget stateful, dan karenanya, itu didefinisikan dengan objek State bernama _MyHomePageState
, yang berisi properti yang memengaruhi tampilan widget. Pertama, mari kita lihat widgetnya:
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
Hal pertama yang harus Anda perhatikan adalah bahwa ini extends StatefulWidget
, mengidentifikasi, oleh karena itu, bahwa ini akan memiliki objek pendamping State
. Widget stateful harus mengganti metode createState() dan mengembalikan instance objek pendamping. Dalam contoh ini, ia mengembalikan sebuah instance dari _MyHomePageState
. State widget yang valid adalah kelas yang memperluas kelas State framework, yang didefinisikan dalam dokumentasi sebagai berikut:
"The logic and internal state for a StatefulWidget."
Selain itu, dalam contoh ini, properti telah diteruskan dari parent widget dan ini muncul di konstruktor widget. Perhatikan bahwa properti title
telah diteruskan dan disimpan di widget di bidang terakhir, yang diberi nama title
. Seperti yang dibahas dalam Bab 4, Kelas dan Konstruksi Dart, Dart memiliki beberapa pintasan cerdas dalam cara menyusun konstruktor, dan dengan menggunakan this
.title
di badan konstruktor ini, kita dapat secara otomatis menetapkan nilai properti title
ke bidang title
.
Biasanya, widget stateful mendefinisikan kelas State
yang sesuai dalam file yang sama. Selain itu, status biasanya bersifat pribadi untuk pustaka widget, karena klien eksternal tidak perlu berinteraksi dengannya secara langsung.
Kelas _MyHomePageState
berikut mewakili objek State dari widget MyHomePage
:
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for
build methods.
);
}
}
Mari kita lihat kode diatas bagian demi bagian.
Pertama, hanya ada satu kelas field, yang bernama _counter
, sehingga Anda dapat menyimpulkan bahwa status widget MyHomePage
ditentukan oleh properti tunggal tersebut. Properti _counter
mencatat jumlah penekanan tombol di sudut kanan bawah layar. Bagaimana perubahan properti _counter
ini akan ditentukan dalam business logic Anda.
Business logic adalah bagian dari kode tempat Anda menentukan aturan bisnis untuk aplikasi Anda. Tidak seperti kebanyakan kode aplikasi Anda, yang berkaitan dengan detail tingkat yang lebih rendah, seperti cara menampilkan widget atau menghubungkan ke database, business logic menentukan bagaimana pengguna berinteraksi dengan aplikasi Anda, dan bagaimana interaksi tersebut memengaruhi data status.
Misalnya, di mana widget ditempatkan di layar, apa warnanya, dan bagaimana reaksinya saat ditekan bukanlah business logic. Namun, jika dengan menekannya, pengguna dapat mengubah informasi tentang diri mereka sendiri, seperti jenis kelamin, alamat rumah, atau berapa banyak kue yang ingin mereka beli, maka itulah logika bisnis (business logic).
Metode pertama yang kita temui adalah metode _incrementCounter
. Ini tidak membutuhkan argumen dan memiliki kode void return yang menentukan bahwa ia tidak mengembalikan nilai. Namun, itu memang melakukan sesuatu yang penting yang harus kita jelajahi lebih detail:
setState(() {
_counter++;
});
Widget stateful dimaksudkan untuk mengubah penampilannya selama masa pakainya – yaitu, mendefinisikan apa yang akan berubah – dan karenanya perlu dibangun kembali untuk mencerminkan perubahan tersebut. Dalam diagram StatefulWidget (Figure 5.2), kita melihat bahwa kerangka kerja membangun kembali StatefulWidget
untuk mencerminkan keadaan baru. Namun, bagaimana kerangka kerja mengetahui kapan sesuatu di widget berubah dan bahwa pembangunan kembali diperlukan?
Jawabannya adalah metode setState
. Metode ini menerima fungsi sebagai parameter yang memperbarui State terkait widget. Dalam hal ini, kami telah membuat fungsi anonim, dan di badan fungsi, kami telah menetapkan bahwa variabel _counter
harus bertambah. Dengan memanggil setState
, kerangka kerja diberi tahu bahwa ia perlu membangun kembali widget. Setelah dipanggil, widget akan digambar ulang dengan nilai _counter
baru yang sudah ditetapkan.
Akhirnya, kita mencapai metode pembuatan widget. Tanda tangan metode dan fungsi yang dimaksud identik dengan metode pembuatan StatelessWidget
yang telah kita bahas sebelumnya. Namun, tidak seperti StatelessWidget
, kami sekarang memiliki status yang akan memengaruhi cara kami menggambar widget, yang dapat mengarah ke kode yang jauh lebih kompleks yang melibatkan lebih banyak pernyataan bersyarat.
Metode build dapat terlihat menakutkan, dan kita akan melihat masing-masing widget secara lebih rinci nanti di bab ini. Namun, pada titik ini, cobalah untuk merasakan struktur komposisi yang ditampilkan. Metode ini mengembalikan widget Scaffold
di tingkat atas dan terdiri dari tiga widget anak melalui tiga argumen konstruktor:
appBar
: Ini menyimpan widget tipe AppBar
, yang memiliki satu argumen konstruktor bernama title
. Seperti yang dapat Anda tebak, ini menjelaskan widget yang akan muncul di bagian atas layar sebagai bilah aplikasi.body
: Ini dapat menampung widget apa pun dan muncul di badan utama aplikasi (yaitu, di antara bilah aplikasi atas dan bilah menu bawah). Dalam hal ini, ia memegang widget Center
(yang memusatkan anak konten). Ini, pada gilirannya, memegang widget Column
(yang membuat kolom widget vertikal). Terakhir, ini menampung dua widget Text
(yang menampilkan string teks).floatingActionButton
: Ini menampung widget jenis FloatingActionButton
, yang merupakan tombol yang mengapung di atas badan aplikasi di sudut kanan bawah (sebagai konfigurasi default) dan berfungsi sebagai tombolPerhatikan bahwa salah satu argumen untuk konstruktor FloatingActionButton
adalah onPressed
, dan nilainya adalah metode _incrementCounter
. Ini mengikat seluruh flow bersama-sama:
MyHomePage
memanggil metode build
dari status pendamping untuk menampilkan bilah aplikasi, isi, dan tombol tindakan._incrementCounter
._incrementCounter
memanggil metode setState
dengan fungsi anonim, menetapkan bahwa variabel _counter
harus bertambah._counter
.build
dari state pendamping lagi untuk menampilkan update app bar, body, dan action button yang diperbarui:Seperti yang ditunjukkan diagram sebelumnya, metode setState
sangat penting untuk keseluruhan flow ini, dan memahami aliran yang digambar ulang ini adalah inti dari cara kerja framework Flutter.
Mari selesaikan bagian ini dengan melihat jenis widget yang kurang terkenal, yaitu jenis InheritedWidget
.
Selain StatelessWidget dan StatefulWidget, ada satu lagi jenis widget di framework Flutter, InheritedWidget. Terkadang, satu widget mungkin memerlukan akses ke data lebih jauh di atas widget tree. Dalam skenario seperti itu, salah satu solusinya adalah mereplikasi informasi ke widget yang tertarik dengan meneruskannya melalui semua widget perantara. Mari kita lihat contoh struktur komposisi widget sehingga kita dapat memeriksanya lebih detail:
Dalam skenario ini, anggaplah salah satu widget di bawah pohon memerlukan akses ke title properti dari widget root. Agar hal ini terjadi di dunia di mana hanya ada widget stateful dan stateless, kita perlu meneruskan properti title
ke setiap child widget melalui konstruktor sehingga pada gilirannya widget turunan dapat meneruskan properti title
ke widget turunannya. Ini dapat menyebabkan banyak kode boilerplate, bisa rawan kesalahan jika salah satu widget tidak dikodekan dengan benar, dan bisa sangat menyakitkan jika diputuskan bahwa child widget memerlukan properti lain, yang berarti bahwa semua perantara widget perlu diperbarui.
Untuk mengatasi masalah ini, Flutter menyediakan kelas InheritedWidget
. Ini adalah jenis widget tambahan yang membantu menyebarkan informasi ke bawah pohon, seperti yang ditunjukkan pada diagram berikut:
Dengan menambahkan InheritedWidget
ke pohon, widget apa pun di bawahnya dapat mengakses data yang dieksposnya dengan menggunakan metode of(InheritedWidget
) dari kelas BuildContext
yang menerima tipe InheritedWidget
sebagai parameter dan menggunakan pohon untuk menemukan widget ancestral pertama dari jenis yang diminta.
Ada beberapa penggunaan InheritedWidget
yang sangat umum di Flutter. Salah satu kegunaan paling umum adalah dari class Theme, yang membantu mendeskripsikan warna untuk keseluruhan aplikasi. Kita akan membahas ini di Bab 6, Menangani Masukan dan Gestur Pengguna.
Sekarang, mari kita selidiki sesuatu yang mungkin telah Anda lihat di beberapa contoh kode sebelumnya, yaitu, properti konstruktor dengan nama key.
Jika Anda melihat konstruktor kelas StatelessWidget
dan StatefulWidget
, Anda akan melihat parameter bernama key. Ini adalah properti penting untuk widget di Flutter.
Properti key memungkinkan Anda untuk mempertahankan status widget di antara pembuatan ulang. Anda mungkin ingat bahwa framework mengambil widget tree dan merendernya ke tree elemen. Tree elemen adalah representasi yang sangat sederhana dari widget tree yang hanya menyimpan jenis widget dan referensi ke widget turunannya. Saat terjadi perubahan atau pembangunan kembali, framework menggunakan tipe widget dan referensi turunan untuk menentukan apakah gambar ulang diperlukan. Dalam situasi di mana ada banyak widget dengan tipe yang sama dengan anak-anak dari widget yang sama (misalnya, baris atau kolom), mungkin ada situasi di mana pengurutan berubah tetapi tidak membatalkan pohon elemen. Dalam situasi ini, perilaku Flutter bisa jadi tidak terduga.
Tanpa key, tree elemen tidak akan tahu state mana yang sesuai dengan widget mana, karena semuanya memiliki tipe yang sama. Ketika sebuah widget memiliki state, ia membutuhkan state yang sesuai untuk dipindahkan dengannya. Sederhananya, itulah yang dilakukan oleh key untuk membantu kerangka kerja. Dengan menahan nilai key, elemen yang bersangkutan akan mengetahui state widget terkait yang harus ada dengannya.
Dalam kebanyakan situasi, key tidak diperlukan (dan tidak boleh digunakan); namun, jika Anda melihat beberapa perilaku aneh di mana Anda yakin widget Anda berubah state tetapi ini tidak tercermin dengan benar di UI, maka ada baiknya memeriksa apakah kerangka kerja salah memahami tree elemen dan apakah key mungkin merupakan obat yang cocok untuk situasi. Jika Anda memerlukan informasi lebih lanjut tentang bagaimana key memengaruhi widget dan jenis key yang tersedia, silakan lihat pengantar dokumentasi resmi untuk key:
https://flutter.dev/docs/development/ui/widgets-intro#keys
.
Kami sekarang telah menjelajahi blok bangunan dasar Flutter: widget. Secara khusus, kami telah melihat tiga jenis widget, stateless, stateful, dan inheritance, bersama dengan situasi di mana Anda akan menggunakannya. Sekarang Anda memiliki pengetahuan dasar tentang dasar-dasar widget, mari kita lihat beberapa widget yang Anda dapatkan gratis saat Anda memulai UI.
Selesaikan langkah-langkah praktikum berikut ini menggunakan editor Visual Studio Code (VS Code) atau Android Studio atau code editor lain kesukaan Anda.
Buka VS Code, lalu tekan tombol Ctrl + Shift + P maka akan tampil Command Palette, lalu ketik Flutter. Pilih New Application Project.
Kemudian buat folder sesuai style laporan praktikum yang Anda pilih. Disarankan pada folder dokumen atau desktop atau alamat folder lain yang tidak terlalu dalam atau panjang. Lalu pilih Select a folder to create the project in.
Buat nama project flutter hello_world seperti berikut, lalu tekan Enter. Tunggu hingga proses pembuatan project baru selesai.
Jika sudah selesai proses pembuatan project baru, pastikan tampilan seperti berikut. Pesan akan tampil berupa "Your Flutter Project is ready!" artinya Anda telah berhasil membuat project Flutter baru.
Melanjutkan dari praktikum 1, silakan selesaikan langkah-langkah berikut ini.
Login ke akun GitHub Anda, lalu buat repository baru dengan nama "flutter-fundamental-part1"
Lalu klik tombol "Create repository" lalu akan tampil seperti gambar berikut.
Kembali ke VS code, project flutter hello_world, buka terminal pada menu Terminal > New Terminal. Lalu ketik perintah berikut untuk inisialisasi git pada project Anda.
git init
Pilih menu Source Control di bagian kiri, lalu lakukan stages (+) pada file .gitignore untuk mengunggah file pertama ke repository GitHub.
Beri pesan commit "tambah gitignore" lalu klik Commit (✔)
Lakukan push dengan klik bagian menu titik tiga > Push
Di pojok kanan bawah akan tampil seperti gambar berikut. Klik "Add Remote"
Salin tautan repository Anda dari browser ke bagian ini, lalu klik Add remote
Setelah berhasil, tulis remote name dengan "origin"
Lakukan hal yang sama pada file README.md mulai dari Langkah 4. Setelah berhasil melakukan push, masukkan username GitHub Anda dan password berupa token yang telah dibuat (pengganti password konvensional ketika Anda login di browser GitHub). Reload halaman repository GitHub Anda, maka akan tampil hasil push kedua file tersebut seperti gambar berikut.
Lakukan push juga untuk semua file lainnya dengan pilih Stage All Changes. Beri pesan commit "project hello_world". Maka akan tampil di repository GitHub Anda seperti berikut.
Kembali ke VS Code, ubah platform di pojok kanan bawah ke emulator atau device atau bisa juga menggunakan browser Chrome. Lalu coba running project hello_world dengan tekan F5 atau Run > Start Debugging. Tunggu proses kompilasi hingga selesai, maka aplikasi flutter pertama Anda akan tampil seperti berikut.
Silakan screenshot seperti pada Langkah 11, namun teks yang ditampilkan dalam aplikasi berupa nama lengkap Anda. Simpan file screenshot dengan nama 01.png pada folder images (buat folder baru jika belum ada) di project hello_world Anda. Lalu ubah isi README.md seperti berikut, sehingga tampil hasil screenshot pada file README.md. Kemudian push ke repository Anda.
Selesaikan langkah-langkah praktikum berikut ini dengan melanjutkan dari praktikum sebelumnya.
Buat folder baru basic_widgets di dalam folder lib. Kemudian buat file baru di dalam basic_widgets dengan nama text_widget.dart
. Ketik atau salin kode program berikut ke project hello_world Anda pada file text_widget.dart
.
import 'package:flutter/material.dart';
class MyTextWidget extends StatelessWidget {
const MyTextWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const Text(
"Nama saya Fulan, sedang belajar Pemrograman Mobile",
style: TextStyle(color: Colors.red, fontSize: 14),
textAlign: TextAlign.center);
}
}
Lakukan import file text_widget.dart
ke main.dart, lalu ganti bagian text widget dengan kode di atas. Maka hasilnya seperti gambar berikut. Screenshot hasil milik Anda, lalu dibuat laporan pada file README.md.
Buat sebuah file image_widget.dart
di dalam folder basic_widgets dengan isi kode berikut.
import 'package:flutter/material.dart';
class MyImageWidget extends StatelessWidget {
const MyImageWidget({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const Image(
image: AssetImage("logo_polinema.jpg")
);
}
}
Lakukan penyesuaian asset pada file pubspec.yaml
dan tambahkan file logo Anda di folder assets
project hello_world.
flutter:
assets:
- logo_polinema.jpg
Jangan lupa sesuaikan kode dan import di file main.dart
kemudian akan tampil gambar seperti berikut.
Selesaikan langkah-langkah praktikum berikut ini dengan melanjutkan project hello_world Anda. Lakukan langkah yang sama seperti pada Praktikum 3, yaitu setiap widget dibuat file sendiri lalu import ke main.dart
dan screenshot hasilnya.
Buat file di basic_widgets > loading_cupertino.dart
. Import stateless widget dari material dan cupertino. Lalu isi kode di dalam method Widget build adalah sebagai berikut.
return MaterialApp(
home: Container(
margin: const EdgeInsets.only(top: 30),
color: Colors.white,
child: Column(
children: <Widget>[
CupertinoButton(
child: const Text("Contoh button"),
onPressed: () {},
),
const CupertinoActivityIndicator(),
],
),
),
);
Button widget terdapat beberapa macam pada flutter yaitu ButtonBar, DropdownButton, TextButton, FloatingActionButton, IconButton, OutlineButton, PopupMenuButton, dan ElevatedButton.
Buat file di basic_widgets > fab_widget.dart
. Import stateless widget dari material. Lalu isi kode di dalam method Widget build adalah sebagai berikut.
return MaterialApp(
home: Scaffold(
floatingActionButton: FloatingActionButton(
onPressed: () {
// Add your onPressed code here!
},
child: const Icon(Icons.thumb_up),
backgroundColor: Colors.pink,
),
),
);
Scaffold widget digunakan untuk mengatur tata letak sesuai dengan material design.
Ubah isi kode main.dart
seperti berikut.
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.red,
),
home: const MyHomePage(title: 'My Increment App'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
bottomNavigationBar: BottomAppBar(
child: Container(
height: 50.0,
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment Counter',
child: const Icon(Icons.add),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
);
}
}
Dialog widget pada flutter memiliki dua jenis dialog yaitu AlertDialog
dan SimpleDialog
.
Ubah isi kode main.dart
seperti berikut.
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: Scaffold(
body: MyLayout(),
),
);
}
}
class MyLayout extends StatelessWidget {
const MyLayout({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: ElevatedButton(
child: const Text('Show alert'),
onPressed: () {
showAlertDialog(context);
},
),
);
}
}
showAlertDialog(BuildContext context) {
// set up the button
Widget okButton = TextButton(
child: const Text("OK"),
onPressed: () {
Navigator.pop(context);
},
);
// set up the AlertDialog
AlertDialog alert = AlertDialog(
title: const Text("My title"),
content: const Text("This is my message."),
actions: [
okButton,
],
);
// show the dialog
showDialog(
context: context,
builder: (BuildContext context) {
return alert;
},
);
}
Flutter menyediakan widget yang dapat menerima input dari pengguna aplikasi yaitu antara lain Checkbox, Date and Time Pickers, Radio Button, Slider, Switch, TextField.
Contoh penggunaan TextField widget adalah sebagai berikut:
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(title: const Text("Contoh TextField")),
body: const TextField(
obscureText: false,
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Nama',
),
),
),
);
}
}
Date and Time Pickers termasuk pada kategori input dan selection widget, berikut adalah contoh penggunaan Date and Time Pickers.
import 'dart:async';
import 'package:flutter/material.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Contoh Date Picker',
home: MyHomePage(title: 'Contoh Date Picker'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// Variable/State untuk mengambil tanggal
DateTime selectedDate = DateTime.now();
// Initial SelectDate FLutter
Future<void> _selectDate(BuildContext context) async {
// Initial DateTime FIinal Picked
final DateTime? picked = await showDatePicker(
context: context,
initialDate: selectedDate,
firstDate: DateTime(2015, 8),
lastDate: DateTime(2101));
if (picked != null && picked != selectedDate) {
setState(() {
selectedDate = picked;
});
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text("${selectedDate.toLocal()}".split(' ')[0]),
const SizedBox(
height: 20.0,
),
ElevatedButton(
onPressed: () => {
_selectDate(context),
// ignore: avoid_print
print(selectedDate.day + selectedDate.month + selectedDate.year)
},
child: const Text('Pilih Tanggal'),
),
],
),
),
);
}
}
README.md
!basic_widgets
, kemudian pada file main.dart
cukup melakukan import widget sesuai masing-masing langkah tersebut!README.md
berisi: capture hasil akhir tiap praktikum (side-by-side, bisa juga berupa file GIF agar terlihat proses perubahan ketika ada aksi dari pengguna) di browser dan perangkat fisik (device) dengan menampilkan NIM dan Nama Anda sebagai ciri pekerjaan Anda. Jika mode developer di perangkat HP Anda belum aktif, silakan cari di internet cara mengaktifkannya!Selamat Anda telah menyelesaikan Codelab ini. Anda telah mempelajari terkait Flutter Fundamental untuk dasar-dasar widget.
Pada codelab berikutnya, Anda akan mempelajari tentang Flutter Fundamental Bagian 2 terkait layout, position, navigasi dan route.
Silakan cek beberapa sumber belajar lainnya: