- Table Of Content
- Pengenalan
- DART
- Lab 1 (Create Flutter Projek)
- Lab 2 (Widget)
- Lab 3 (Widget Part 2)
- Lab 4 (Stateless and Statefull Widget)
- Lab 5 (Navigation)
- Lab 6 (Persistent Local Storage)
- LAB 7 (REST API PART 1 - Authentication)
- Lab 8 (REST API PART 2 - CRUD)
Merupakan bahasa pemrograman asynchronous berbasis OOP yang dapat digunakan untuk membuat aplikasi di segala platform
Sebuah framework yang digunakan pada bahasa pemrograman dart untuk membuat tampilan atau ui.
Instalasi Flutter dapat dimulai dengan menginstall Android Studio seperti biasa lalu kemudian bisa ikuti langkah langkah instalasi pada dokumentasi instalasi flutter sebagai berikut Dokumentasi Instalasi Flutter
Untuk IDE yang digunakan bisa menggunakan android studio langsung atau menggunakan IDE lain seperti Visual Studio Code. Dengan alasan tertentu penulis lebih suka menggunakan Visual Studio Code sehingga penulis menggunakan Visual Studio Code dengan menginstall ekstensi flutter pada Visual Studio Code
Pada dasarnya syntax dan fitur pada dart tidak jauh berbeda dengan bahasa pemrograman lain. jadi jika sudah pernah menggunakan bahasa OOP lain hanya perlu penyesuaian sedikit bahkan bahasa dart ini terbilang cukup lebih mudah
Dart mendukung proses asinkronus dimana dart dapat mengeksekusi tugas-tugas secara non-bloking (Mirip Seperti Javascript).
Pada kebanyakan bahasa pemrograman (PHP, Java, Golang, Python), menggunakan konsep blocking dimana jika ada Task 1 dan Task 2, Task 2 akan dijalankan setelah Task 1 benar-benar selesai di proses.
Sedangkan pada bahasa Asinkronus jika ada Task 1 dan Task 2, Task 2 akan dijalankan setelah Task 1 sudah dieksekusi (Tanpa perlu proses nya selesai, yang penting di eksekusi)
Untuk menginisiasi projek flutter dapat menggunakan perintah berikut
flutter create lab1Perintah tersebut akan membuat directory dengan nama lab1 dimana direktori tersebut adalah projek flutter kita
Inisiasi proyek juga dapat dilakukan menggunakan GUI Visual Studio Code seperti berikut
Flutter memiliki satu main file, dimana file tersebut yang akan dieksekusi saat aplikasi flutter dijalankan file tersebut terletak di lib/main.dart
Semua yang ada pada UI Flutter merupakan sebuah Widget yang saling berkaitan, bahkan saat kita membuat sebuah halaman atau tampilan itu juga akan menjadi widget
Widget yang digunakan sebagai titik awal dalam membangun aplikasi dengan desain Material. MaterialApp menyiapkan banyak konfigurasi dasar dan menyediakan struktur dasar yang diperlukan untuk mengembangkan aplikasi Flutter dengan tampilan Material Design.
Dalam Flutter, Scaffold adalah widget yang digunakan sebagai kerangka dasar untuk membangun antarmuka aplikasi. Scaffold menyediakan struktur umum yang umumnya ditemukan dalam aplikasi, seperti AppBar, body, drawer, dan sebagainya
Dalam Flutter memiliki beberapa widget untuk keperluan layouting sebagai berikut
Container Merupakan sebuah widget yang berfungsi sebagai wadah dari widget utama yang ingin ditampilkan (Button, Text, dll). Dikatakan sebuah wadah karena widget sering digunakan untuk mengatur padding, margin, background untuk widget dibawahnya berikut contoh untuk pemanggilan widget Container, dimana terlihat Widget Container sebagai widget parent dan child nya adalah widget Text
Container(
color: Colors.red,
padding: EdgeInsets.all(20),
child: Text("Text Container 1"),
)Column merupakan sebuah widget yang berfungsi juga sebagai wadah, bedanya dengan Container widget ini dapat memiliki lebih dari 1 Child yang nanti nya akan di render secara vertikal
Column(
children: [
Container(child: Text("Text1")),
Container(child: Text("Text2"))
]
)Row merupakan sebuah widget yang berfungsi juga sebagai wadah dan memiliki lebih dari 1 child bedanya dengan column widget didalam sini akan dirender secara horizontal
Row(
children: [
Container(child: Text("Text1")),
Container(child: Text("Text2"))
]
)Sebuah widget wadah dimana widget ini akan menggunakan semua ruang tersisa pada widget parent nya
Row(
children: [
Container(child:
Text("Text1")
),
Expanded(
child: Container(
child: Text("Text2")
)
)
]
)Pada projek lab2 anda bisa melihat contoh penggunaan dan perpaduan widget diatas dengan beberapa tambahan widget lain

Pada bagian ini akan menunjukan beberapa contoh widget lain yang umum digunakan dan salah cara merender widget dengan menggunakan konsep looping
Pada dasarnya ukuran halaman pada UI flutter akan mengikuti panjang dan lebar device nya, sehingga jika kita ingin membuat tampilan list yang sangat panjang kita memerlukan widget ini untuk dapat memanggunakan ukuran list yang panjang atau lebarnya melebihi ukuran device dan akan ditampilkan dalam bentuk scrolling
ListView(
children: [
Text("1"),
Text("2"),
Text("3"),
Text("4"),
Text("5"),
]
)Widget untuk menampilkan sebuah text
const Text(
"Catat\nPengeluaran",
style: TextStyle(
color: Color(0xFF141414),
fontWeight: FontWeight.w700,
fontSize: 35,
),
),Widget untuk membuat sebuah inputan text
TextField(
cursorColor: Color(0xFF141414),
decoration: InputDecoration(
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(15),
),
borderSide: BorderSide(
color: Color(0xFF141414),
width: 2.0,
),
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(15),
),
borderSide: BorderSide(
color: Color(0xFF141414),
width: 2.0,
),
),
labelText: 'Jumlah Pengeluaran',
labelStyle: TextStyle(
color: Color(0xFF141414),
),
),
)Widget untuk membuat sebuah button yang nantinya bisa menerima trigger tap
ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xFF141414),
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(10.0),
),
),
onPressed: () {},
child: const Text('Submit'),
)Card(
child: Text("tes")
)Untuk praktek pada lab 3 akan membuat sebuah tampilan seperti berikut (Sudah disediakan template pada folder lab3 dan hasilnya ada di lab3_final)
Pada dasar nya Widget pada flutter ada 2 jenis, Stateless dan Statefull widget, sesuai namanya perbedaan keduanya ada pada ada atau tidak nya state/keadaan pada widget tersebut.
Stateless Widget adalah widget yang state/keadaan nya selalu tetap dan tidak berubah-ubah semenjak di inisiasi, jenis widget ini biasa digunakan untuk widget-widget kecil yang dibuat untuk di panggil di tempat lain sebagai reusable widget/component, contohnya jika kita membuat custom form yang akan kita gunakan berkali-kali di berbagai tempat kita akan menggunakan stateless widget untuk membuat widget/komponen tersebut.
Statefull Widget adalah widget yang state/keadaan nya dapat berubah ubah semenjak di inisiasi, jenis widget ini biasa digunakan untuk membuat halaman yang memiliki interaksi yang merubah state/keadaan halaman tersebut. contohnya jika kita membuat halaman kalkulator tentunya akan ada interaksi di halaman tersebut yang merubah keaadaan pada halaman tersebut
Praktek disini akan terdiri dari beberapa tahap
Pada praktek ini akan menggunakan projek lab4 sebagai template dan hasil dari praktek ini sudah ada di projek lab4_interaksi. Goal dari praktik ini adalah menerima inputan user dan menambahkan nya ke list yang sudah ada. Berikut hasilnya
Pada praktek ini akan menggunakan projek lab4_interaksi sebgai template dan hasil dari praktek ini sudah ada di projek lab4_final. Goal dari praktik ini adalah membagi bagi code yang panjang menjadi beberapa bagian dan memanggilanya
Pada lab ini akan mempelajari bagaimana melakukan navigasi pada flutter, pada folder lab5 sudah disiapkan projek yang sudah disiapkan 5 screen sebagai berikut tetapi belum ada navigasi antar screen tersebut
Pada umumnya pada Flutter memiliki 3 cara navigasi yaitu
- Menggunakan Navigator
- Menggunakan Named Routes
- Menggunakan Third Party Libraries yang berfungsi sebagai route management (Bisanya jika butuh fitur lebih)
berikut contoh untuk berpindah ke halaman LoginPage menggunakan Navigator, anda bisa menggunakan script dibawah pada trigger onTap atau lainya
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const LoginPage(),
),
);Jika kamu ingin membawa sebuah data ke screen selanjutnya anda bisa mengkonfigurasi Screen tujuan untuk menerima parameter seperti berikut
class ExpenseDetailPage extends StatelessWidget {
final String amount;
final String description;
const ExpenseDetailPage({
super.key,
required this.amount,
required this.description,
});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Row(
children: [Text(amount), Text(description)]
)
);
}
}diatas adalah contoh jika screen selanjutnya merupakan stateless widget,berikut jika screen selanjutnya merupakan statefull widget
import 'package:flutter/material.dart';
class ExpenseDetailPage extends StatefulWidget {
final String amount;
final String description;
const ExpenseDetailPage({
super.key,
required this.amount,
required this.description,
});
@override
State<ExpenseDetailPage> createState() => _ExpenseDetailPageState();
}
class _ExpenseDetailPageState extends State<ExpenseDetailPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Row(children: [Text(widget.amount), Text(widget.description)])
);
}
}Lalu anda bisa berpindah halaman dengan kode berikut
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => const ExpenseDetailPage(amount: "5000", description: "Lorem Ipsum Dolor Sit Amet"),
),
);Named route merupakan metode navigasi menggunakan nama route dalam bentuk strings untuk berpindah pindah halaman, untuk menggunakan named route kita perlu menndefinisika nama route dan kelas screen nya untuk tiap route pada MaterialApp seperti berikut
MaterialApp(
title: 'Expense Tracker',
initialRoute: '/',
routes: {
'/': (context) => SplashPage(),
'/home': (context) => HomePage(),
'/login': (context) => LoginPage(),
'/signup': (context) => SignupPage(),
'/detail': (context) => ExpenseDetailPage()
},
);Lalu kita dapat berpindah halaman menggunakan kode berikut
Navigator.pushNamed(context, '/signup');Local Storaga merupakan sebuah tempat penyimpanan persistent yang disimpan pada disk device, pada flutter untuk mengakses jenis penyimpanan ini bisa menggunakan berbagai library third party seperti shared_preferences, get_storage, localstorage, sqflite.
Penggunaan library-libray tersebut tergantung kebutuhan, semua library yang saya sebutkan sebelumnya kecuali sqflite dapat menyimpan data dalam bentuk key-value.
Penggunaan key-value yang disimpan pada persistent storage di local paling sering digunakan untuk menyimpan data autentikasi user. dan pada Lab 6 ini akan mencoba menerapkan kasus tersebut.
Pada praktek ini akan menggunakan template yang ada di folder lab6 dan hasil final akan ada di lab6_final. pada lab ini akan mempraktikkan penyimpanan email ke SharedPreferences
Contoh Penggunaan shared preferences :
- Menyimpan data (menyimpan data dengan key
emaildan valuedhevanthareza@gmail.com)
final storage = await SharedPreferences.getInstance();
storage.setString("email", "dhevanthareza@gmail.com");- Mengambil data (mengambil data dari key
email)
final storage = await SharedPreferences.getInstance();
String _userEmail = storage.getString("email") ?? "-";- Menghapus data (menghapus data dari key
email)
final storage = await SharedPreferences.getInstance();
storage.remove("email");Pada lab ini akan mempraktikkan proses terkoneksi dengan api dan di implementasikan untuk proses registrasi dan proses login.
API (Application Programming Interface) merupakan sebuah interface yang digunakan agar sebuah aplikasi dapat berkomunikasi dengan aplikasi lain. Interface nya pun bermacam-macam seperti REST, SOCKET, GRPC dll
Pada lab ini akan menggunakan interface REST untuk berkomunikasi dengan aplikasi server side yang terhubung langsung ke database.
Untuk dapat terkoneksi dengan aplikasi server side menggunakan interface REST kita membutuhkan Http Client. pada flutter sudah ada beberapa library untuk Http Client seperti http,retrofit,dio, dll
You can setup the api on
https://github.com/dhevanthareza/expense-api
Pada praktik ini akan menggunkan library dio untuk terkoneksi dengan http client.
- Instalasi Dio
dart pub add dio
- Menyiapkan Intance Dio, sebenarnya untuk menggunakan dio kita tidak perlu membuat instance, pembuatan instance diperlukan untuk mendefinisikan Base Url agar tidak perlu di definisikan berulang-ulang. Selain Base Url juga dapat membuat opsi opsi lain. Pada lab 8 juga membuat beberapa fungsi khusus untuk handle kejadian kejadian tertentu agar kita tidak perlu melakukan handling berkali-kalo. Berikut instance Dio yang dibuat
class RestClient { static final client = () async { var dio = Dio( BaseOptions( followRedirects: true, headers: {"Accept": "application/json"}, connectTimeout: Duration(seconds: 20), receiveTimeout: Duration(seconds: 20), baseUrl: "http://192.168.41.132:4001", ), ); dio.interceptors.add(PrettyDioLogger()); final storage = await SharedPreferences.getInstance(); String? accessToken = storage.getString("accessToken"); if (accessToken != null) { dio.options.headers['Authorization'] = "Bearer $accessToken"; } return dio; }; static dynamic _returnResponse(Response? response) { if (response == null) { throw Exception('Tidak dapat terkoneksi dengan API'); } return _handleResponse(response); } static dynamic _returnErr(DioException err) { print(err); Response? response = err.response; if (response == null) { throw Exception(err.message ?? "HTTP ERROR"); } return _handleResponse(response); } static _handleResponse(Response response) { if (response.statusCode == 200) { var responseJson = response.data; return responseJson; } throw Exception( response.data != null ? response.data['message'] : 'Undefined Error', ); } static Future<dynamic> get(String url, {Map<String, dynamic>? queryParameter}) async { dynamic responseJson; try { Dio _client = await client(); dynamic response = await _client.get(url, queryParameters: queryParameter); responseJson = _returnResponse(response); return responseJson; } on SocketException { throw Exception('No Internet connection'); } on DioException catch (err) { responseJson = _returnErr(err); } return responseJson; } static Future<dynamic> post(String url, {dynamic data}) async { dynamic responseJson; Response response; try { Dio _client = await client(); response = await _client.post(url, data: data); responseJson = _returnResponse(response); } on SocketException { throw Exception('No Internet connection'); } on DioException catch (err) { responseJson = _returnErr(err); } return responseJson; } static Future<dynamic> patch(String url, {dynamic data}) async { dynamic responseJson; Response response; try { Dio _client = await client(); response = await _client.patch(url, data: data); responseJson = _returnResponse(response); return responseJson; } on SocketException { throw Exception('No Internet connection'); } on DioException catch (err) { responseJson = _returnErr(err); } return responseJson; } static Future<dynamic> delete(String url, {dynamic data}) async { dynamic responseJson; Response response; try { Dio _client = await client(); response = await _client.delete(url, data: data); responseJson = _returnResponse(response); return responseJson; } on SocketException { throw Exception('No Internet connection'); } on DioException catch (err) { responseJson = _returnErr(err); } return responseJson; } }
- Berikut contoh penggunaan dari instance dio diatas
await RestClient.get('/expense');
await RestClient.post('/expense', data: {"description": "description", "amount": "amount"});
await RestClient.patch('/expense/1', data: {"description": "description", "amount": "amount"});
await RestClient.delete('/expense/1');
Pada lab ini akan mempraktikan proses CRUD yang langsung terkoneksi dengan Aplikasi Server Side menggunakan Http Client Dio. Hasil dari lab ini bisa anda lihat pada lab8_final











