Tutorial Flutter: Menggunakan Aplikasi CRUD REST API Android dan iOS - Demo iOS

Tutorial Flutter: Menggunakan Aplikasi CRUD REST API Android dan iOS

Tutorial Flutter: Menggunakan Aplikasi CRUD REST API Android dan iOS

 

Tutorial Flutter langkah demi langkah yang komprehensif tentang membangun aplikasi Android dan iOS yang menggunakan CRUD REST API

Dalam tutorial Flutter ini, kami akan menunjukkan cara membuat aplikasi Android dan iOS yang menggunakan CRUD REST API. Hampir semua aplikasi Android dan iOS mengakses data menggunakan REST API. Di aplikasi Flutter, persyaratan ini akan dilakukan menggunakan paket HTTP. Kami akan menggunakan REST API Node-Express-MongoDB sederhana kami sebagai backend API REST. Jadi, kami akan memfokuskan tutorial ini tentang cara mengakses REST API menggunakan paket HTTP Flutter.

Tutorial ini dibagi menjadi beberapa langkah:

  • Langkah # 1: Persiapan
  • Langkah # 2: Buat Aplikasi Flutter
  • Langkah # 3: Buat Layanan HTTP Flutter
  • Langkah # 4: Tampilkan Daftar Data
  • Langkah # 5: Tampilkan Detail Data
  • Langkah # 6: Tambahkan Data Baru
  • Langkah # 7: Edit Data
  • Langkah # 8: Jalankan dan Uji Aplikasi Flutter ke Perangkat Android dan iOS

Alat, kerangka kerja, dan pustaka berikut diperlukan untuk tutorial ini:

  1. Flutter SDK
  2. API REST Node-Express
  3. SDK Android
  4. Xcode
  5. Terminal (di Mac / Linux) atau CMD (di Windows)
  6. IDE (Android Studio / IntelliJ / Visual Studio Code)

Mari kita mulai ke langkah utama!

Anda dapat menonton tutorial video di saluran YouTube kami di sini . Silakan suka, bagikan, komentar, dan berlangganan saluran YouTube Anda.

Langkah # 1: Persiapan

Pasang Flutter SDK

Untuk menginstal flutter SDK, pertama-tama kita harus mendownload flutter_macos_1.20.0-stable.zip  kemudian mengekstrak file tersebut ke lokasi yang Anda inginkan.

cd ~/development

unzip ~/Downloads/flutter_macos_1.20.0-stable.zip

Selanjutnya, tambahkan alat flutter ke jalur.

export PATH=”$PATH:~/development/flutter/bin”

Selanjutnya, agar binari iOS dan Android dapat diunduh sebelumnya, ketikkan perintah Flutter ini.

flutter precache

Periksa Dependensi yang Diperlukan

Untuk memeriksa lingkungan dan menampilkan laporan ke jendela terminal untuk menemukan dependensi yang diperlukan untuk menginstal, ketik perintah ini.

flutter doctor

Kami memiliki ringkasan ini di Terminal.

Doctor summary (to see all details, run flutter doctor -v):

[✓] Flutter (Channel stable, v1.20.0-stable, on Mac OS X 10.14.6 18G2022,

locale en-ID)

[!] Android toolchain – develop for Android devices (Android SDK version

29.0.0-rc1)

! Some Android licenses not accepted.  To resolve this, run: flutter doctor

–android-licenses

[✓] Xcode – develop for iOS and macOS (Xcode 10.3)

[✓] Android Studio (version 3.4)

[✓] VS Code (version 1.37.1)

[!] Connected device

! No devices available

! Doctor found issues in 2 categories.

Untuk memperbaiki, masalah seperti ini, cukup hubungkan perangkat Android dan perbarui lisensi Android dengan mengetikkan perintah ini.

flutter doctor –android-licenses

Ketik `y` untuk setiap pertanyaan yang ditampilkan di terminal. Selanjutnya, periksa perangkat Android yang terhubung dengan mengetikkan perintah ini.

adb devices

List of devices attached

FUZDON75YLOVVC5S    device

Siapkan IDE

Kita perlu menyiapkan IDE agar berfungsi dengan aplikasi Flutter dengan mudah dan kompatibel. Mulai Android Studio (kami akan menggunakan IDE ini) lalu buka Menu Android Studio -> Preferensi.

Tutorial Flutter: Menggunakan Aplikasi CRUD REST API Android dan iOS - Plugin Android Studio

Pilih plugin di panel kiri.

Tutorial Flutter: Menggunakan Aplikasi CRUD REST API Android dan iOS - Pilih Plugin

Ketik Flutter di pasar plugin lalu tekan Enter. Selanjutnya, klik tombol Instal di Flutter. Jika ada prompt untuk menginstal Dart, klik Yes. Mulai ulang IDE jika diminta untuk memulai ulang.

Sekarang, Flutter siap mengembangkan aplikasi seluler Android dan iOS.

Langkah # 2: Buat Aplikasi Flutter

Setelah penyiapan IDE selesai, ini akan kembali ke dialog awal Android.

Tutorial Flutter: Menggunakan Aplikasi CRUD REST API Android dan iOS - Selamat Datang di Android Studio

Pilih `Start a New Flutter Project` lalu pilih` Flutter Application`.

Tutorial Flutter: Menggunakan Aplikasi CRUD REST API Android dan iOS - Proyek Flutter Baru

Klik Tombol Berikutnya, lalu isi bidang yang diperlukan dan pilih jalur SDK Flutter yang diinstal sebelumnya.

Tutorial Flutter: Menggunakan Aplikasi CRUD REST API Android dan iOS - Nama Proyek

Klik tombol berikutnya, lalu isi nama paket dengan domain Anda sendiri dan kosongkan “Sertakan dukungan Kotlin untuk kode Android” dan “Sertakan dukungan Swift untuk kode iOS”.

Tutorial Flutter: Menggunakan Aplikasi CRUD REST API Android dan iOS - Nama Paket

Klik tombol Selesai dan pembuatan aplikasi Flutter sedang berlangsung. Selanjutnya, jalankan aplikasi Flutter untuk pertama kalinya. Di toolbar Android Studio, pilih perangkat dan main.dart lalu klik tombol putar.

Tutorial Flutter: Menggunakan Aplikasi CRUD REST API Android dan iOS - Toolbar Android Studio

Aplikasi Flutter awal terlihat seperti ini di perangkat Android.

Tutorial Flutter: Menggunakan Aplikasi CRUD REST API Android dan iOS - Demo Flutter

Langkah # 3: Buat Layanan HTTP Flutter

Seperti yang kami sebutkan di paragraf pertama, kami akan menggunakan paket perpustakaan HTTP untuk mengakses RESTful API dari server REST API. Untuk itu install package ini dengan open dan edit pubspec.yaml lalu tambahkan dependency ini.

dependencies:

flutter:

sdk: flutter

# The following adds the Cupertino Icons font to your application.

# Use with the CupertinoIcons class for iOS style icons.

cupertino_icons: ^0.1.3

http: ^0.12.2

Selanjutnya, klik tombol “Paket mendapatkan” di perintah Flutter di bagian atas konten pubspec.yml. Perintah itu akan menginstal dependensi yang terdaftar.

Tutorial Flutter: Menggunakan Aplikasi CRUD REST API Android dan iOS - Pub Get

Selanjutnya, buat paket dan kelas atau objek `lib / models / cases.dart` yang mewakili tabel SQLite. Kelas ini tentang kasus virus korona. Jadi, konten kelas ini harus seperti ini.

class Cases {

final String id;

final String name;

final String gender;

final int age;

final String address;

final String city;

final String country;

final String status;

final String updated;

Cases({ this.id, this.name, this.gender, this.age, this.address, this.city, this.country, this.status, this.updated });

factory Cases.fromJson(Map<String, dynamic> json) {

return Cases(

id: json[‘_id’] as String,

name: json[‘name’] as String,

gender: json[‘gender’] as String,

age: json[‘age’] as int,

address: json[‘address’] as String,

city: json[‘city’] as String,

country: json[‘country’] as String,

status: json[‘status’] as String,

updated: json[‘updated’] as String,

);

}

@override

String toString() {

return ‘Cases{id: $id, name: $name, age: $age}’;

}

}

Selanjutnya, buat paket dan kelas atau objek `lib / services / api_service.dart` di mana kita akan meletakkan semua metode CRUD (POST, GET, PUT, DELETE) ke REST API. Isi kelas ini dengan operasi CRUD permintaan HTTP ini ke REST API.

import ‘dart:convert’;

import ‘package:flutter_restapi/models/cases.dart’;

import ‘package:http/http.dart’;

class ApiService {

final String apiUrl = “http://192.168.0.7:3000/api“;

Future<List<Cases>> getCases() async {

Response res = await get(apiUrl);

if (res.statusCode == 200) {

List<dynamic> body = jsonDecode(res.body);

List<Cases> cases = body.map((dynamic item) => Cases.fromJson(item)).toList();

return cases;

} else {

throw “Failed to load cases list”;

}

}

Future<Cases> getCaseById(String id) async {

final response = await get(‘$apiUrl/$id’);

if (response.statusCode == 200) {

return Cases.fromJson(json.decode(response.body));

} else {

throw Exception(‘Failed to load a case’);

}

}

Future<Cases> createCase(Cases cases) async {

Map data = {

‘name’: cases.name,

‘gender’: cases.gender,

‘age’: cases.age,

‘address’: cases.address,

‘city’: cases.city,

‘country’: cases.country,

‘status’: cases.status

};

final Response response = await post(

apiUrl,

headers: <String, String>{

‘Content-Type’: ‘application/json; charset=UTF-8’,

},

body: jsonEncode(data),

);

if (response.statusCode == 200) {

return Cases.fromJson(json.decode(response.body));

} else {

throw Exception(‘Failed to post cases’);

}

}

Future<Cases> updateCases(String id, Cases cases) async {

Map data = {

‘name’: cases.name,

‘gender’: cases.gender,

‘age’: cases.age,

‘address’: cases.address,

‘city’: cases.city,

‘country’: cases.country,

‘status’: cases.status

};

final Response response = await put(

‘$apiUrl/$id’,

headers: <String, String>{

‘Content-Type’: ‘application/json; charset=UTF-8’,

},

body: jsonEncode(data),

);

if (response.statusCode == 200) {

return Cases.fromJson(json.decode(response.body));

} else {

throw Exception(‘Failed to update a case’);

}

}

Future<void> deleteCase(String id) async {

Response res = await delete(‘$apiUrl/$id’);

if (res.statusCode == 200) {

print(“Case deleted”);

} else {

throw “Failed to delete a case.”;

}

}

}

Langkah # 4: Tampilkan Daftar Data

Kami akan menampilkan daftar data dalam file Dart terpisah yang akan dipanggil dari badan halaman utama main.dart. Untuk itu diperlukan file dart untuk melihat daftar datanya. Buat file lib / caseslist.dart lalu tambahkan impor ini.

import ‘package:flutter/material.dart’;

import ‘package:flutter_restapi/models/cases.dart’;

import ‘detailwidget.dart’;

Buat nama kelas yang memperluas objek StatelessWidget.

class CasesList extends StatelessWidget {

}

Di dalam kelas itu, nyatakan variabel ini yang menyimpan daftar Kasus yang dimuat dari main.dart dan buat Kunci untuk daftar tersebut.

final List<Cases> cases;

CasesList({Key key, this.cases}) : super(key: key);

Tambahkan metode penggantian setelah variabel untuk membuat widget ListView untuk daftar kasus.

@override

Widget build(BuildContext context) {

return

ListView.builder(

itemCount: cases == null ? 0 : cases.length,

itemBuilder: (BuildContext context, int index) {

return

Card(

child: InkWell(

onTap: () {

Navigator.push(

context,

MaterialPageRoute(

builder: (context) => DetailWidget(cases[index])),

);

},

child: ListTile(

leading: Icon(Icons.person),

title: Text(cases[index].name),

subtitle: Text(cases[index].age.toString()),

),

)

);

});

}

Pembuat ListView itu berisi Kartu yang memiliki turunan InkWell yang digunakan untuk menavigasi ke DetailWidget menggunakan MaterialPageRoute. Anak Kartu adalah ListTile yang berisi Ikon (terdepan), Teks (judul), dan Teks (subtitle).

Widget InkWell memiliki acara onTap dengan tindakan untuk Menavigasi ke halaman detail. Container, Column, Image, dan Text memiliki propertinya masing-masing untuk menyesuaikan gaya atau tata letak.

Perlu diingat, setiap widget yang menggunakan child hanya memiliki satu widget sebagai anaknya. Jika Anda perlu meletakkan lebih dari satu widget ke widget induk, gunakan properti children: <Widget>.

Selanjutnya, buka dan edit lib / main.dart lalu ganti semua kode Dart dengan baris kode ini untuk menampilkan ListView di halaman beranda utama.

import ‘package:flutter/material.dart’;

import ‘package:flutter_restapi/adddatawidget.dart’;

import ‘dart:async’;

import ‘package:flutter_restapi/models/cases.dart’;

import ‘package:flutter_restapi/services/api_service.dart’;

import ‘package:flutter_restapi/caseslist.dart’;

void main() {

runApp(MyApp());

}

class MyApp extends StatelessWidget {

// This widget is the root of your application.

@override

Widget build(BuildContext context) {

return MaterialApp(

title: ‘Flutter Demo’,

theme: ThemeData(

// This is the theme of your application.

//

// Try running your application with “flutter run”. You’ll see the

// application has a blue toolbar. Then, without quitting the app, try

// changing the primarySwatch below to Colors.green and then invoke

// “hot reload” (press “r” in the console where you ran “flutter run”,

// or simply save your changes to “hot reload” in a Flutter IDE).

// Notice that the counter didn’t reset back to zero; the application

// is not restarted.

primarySwatch: Colors.blue,

// This makes the visual density adapt to the platform that you run

// the app on. For desktop platforms, the controls will be smaller and

// closer together (more dense) than on mobile platforms.

visualDensity: VisualDensity.adaptivePlatformDensity,

),

home: MyHomePage(title: ‘Flutter Demo Home Page’),

);

}

}

class MyHomePage extends StatefulWidget {

MyHomePage({Key key, this.title}) : super(key: key);

// This widget is the home page of your application. It is stateful, meaning

// that it has a State object (defined below) that contains fields that affect

// how it looks.

// This class is the configuration for the state. It holds the values (in this

// case the title) provided by the parent (in this case the App widget) and

// used by the build method of the State. Fields in a Widget subclass are

// always marked “final”.

final String title;

@override

_MyHomePageState createState() => _MyHomePageState();

}

class _MyHomePageState extends State<MyHomePage> {

final ApiService api = ApiService();

List<Cases> casesList;

@override

Widget build(BuildContext context) {

if(casesList == null) {

casesList = List<Cases>();

}

// This method is rerun every time setState is called, for instance as done

// by the _incrementCounter method above.

//

// The Flutter framework has been optimized to make rerunning build methods

// fast, so that you can just rebuild anything that needs updating rather

// than having to individually change instances of widgets.

return Scaffold(

appBar: AppBar(

// Here we take the value from the MyHomePage object that was created by

// the App.build method, and use it to set our appbar title.

title: Text(widget.title),

),

body: new Container(

child: new Center(

child: new FutureBuilder(

future: loadList(),

builder: (context, snapshot) {

return casesList.length > 0? new CasesList(cases: casesList):

new Center(child:

new Text(‘No data found, tap plus button to add!’, style: Theme.of(context).textTheme.title));

},

)

),

),

floatingActionButton: FloatingActionButton(

onPressed: () {

_navigateToAddScreen(context);

},

tooltip: ‘Increment’,

child: Icon(Icons.add),

), // This trailing comma makes auto-formatting nicer for build methods.

);

}

Future loadList() {

Future<List<Cases>> futureCases = api.getCases();

futureCases.then((casesList) {

setState(() {

this.casesList = casesList;

});

});

return futureCases;

}

_navigateToAddScreen (BuildContext context) async {

final result = await Navigator.push(

context,

MaterialPageRoute(builder: (context) => AddDataWidget()),

);

}

}

Kami menggunakan tombol mengambang yang ada sebagai tombol tambah data dengan tindakan untuk pergi ke AddDataWidget.dart.

Langkah # 5: Tampilkan Detail Data

Kami akan menampilkan detail data ke halaman lain yang terbuka saat mengetuk item daftar di halaman daftar. Untuk itu buat file Dart di folder lib dulu lib / detailwidget.dart. Kami akan menggunakan widget Kartu yang dapat digulir untuk menampilkan detail untuk mencegah luapan jika konten Kartu lebih panjang. Selanjutnya, buka dan edit lib / detailwidget.dart lalu tambahkan impor bahan Flutter, pembantu database, editdatawidget, dan model objek kasus ini.

import ‘package:flutter/material.dart’;

import ‘services/api_service.dart’;

import ‘editdatawidget.dart’;

import ‘models/cases.dart’;

Tambahkan kelas DetailWidget yang memperluas StatefulWidget. Kelas ini memiliki konstruktor dengan bidang objek, bidang objek Kasus, dan _DetailWidgetState yang membangun tampilan untuk detail data.

class DetailWidget extends StatefulWidget {

DetailWidget(this.cases);

final Cases cases;

@override

_DetailWidgetState createState() => _DetailWidgetState();

}

Tambahkan kelas _DetailWidgetState yang menerapkan semua widget yang diperlukan untuk menampilkan detail data.

class _DetailWidgetState extends State<DetailWidget> {

_DetailWidgetState();

final ApiService api = ApiService();

@override

Widget build(BuildContext context) {

return Scaffold(

appBar: AppBar(

title: Text(‘Details’),

),

body: SingleChildScrollView(

child: Container(

padding: EdgeInsets.all(20.0),

child: Card(

child: Container(

padding: EdgeInsets.all(10.0),

width: 440,

child: Column(

children: <Widget>[

Container(

margin: EdgeInsets.fromLTRB(0, 0, 0, 10),

child: Column(

children: <Widget>[

Text(‘Name:’, style: TextStyle(color: Colors.black.withOpacity(0.8))),

Text(widget.cases.name, style: Theme.of(context).textTheme.title)

],

),

),

Container(

margin: EdgeInsets.fromLTRB(0, 0, 0, 10),

child: Column(

children: <Widget>[

Text(‘Gender:’, style: TextStyle(color: Colors.black.withOpacity(0.8))),

Text(widget.cases.gender, style: Theme.of(context).textTheme.title)

],

),

),

Container(

margin: EdgeInsets.fromLTRB(0, 0, 0, 10),

child: Column(

children: <Widget>[

Text(‘Age:’, style: TextStyle(color: Colors.black.withOpacity(0.8))),

Text(widget.cases.age.toString(), style: Theme.of(context).textTheme.title)

],

),

),

Container(

margin: EdgeInsets.fromLTRB(0, 0, 0, 10),

child: Column(

children: <Widget>[

Text(‘Address:’, style: TextStyle(color: Colors.black.withOpacity(0.8))),

Text(widget.cases.address, style: Theme.of(context).textTheme.title)

],

),

),

Container(

margin: EdgeInsets.fromLTRB(0, 0, 0, 10),

child: Column(

children: <Widget>[

Text(‘City:’, style: TextStyle(color: Colors.black.withOpacity(0.8))),

Text(widget.cases.city, style: Theme.of(context).textTheme.title)

],

),

),

Container(

margin: EdgeInsets.fromLTRB(0, 0, 0, 10),

child: Column(

children: <Widget>[

Text(‘Country:’, style: TextStyle(color: Colors.black.withOpacity(0.8))),

Text(widget.cases.country, style: Theme.of(context).textTheme.title)

],

),

),

Container(

margin: EdgeInsets.fromLTRB(0, 0, 0, 10),

child: Column(

children: <Widget>[

Text(‘Status:’, style: TextStyle(color: Colors.black.withOpacity(0.8))),

Text(widget.cases.status, style: Theme.of(context).textTheme.title)

],

),

),

Container(

margin: EdgeInsets.fromLTRB(0, 0, 0, 10),

child: Column(

children: <Widget>[

Text(‘Update Date:’, style: TextStyle(color: Colors.black.withOpacity(0.8))),

Text(widget.cases.updated, style: Theme.of(context).textTheme.title)

],

),

),

Container(

margin: EdgeInsets.fromLTRB(0, 0, 0, 10),

child: Column(

children: <Widget>[

RaisedButton(

splashColor: Colors.red,

onPressed: () {

_navigateToEditScreen(context, widget.cases);

},

child: Text(‘Edit’, style: TextStyle(color: Colors.white)),

color: Colors.blue,

),

RaisedButton(

splashColor: Colors.red,

onPressed: () {

_confirmDialog();

},

child: Text(‘Delete’, style: TextStyle(color: Colors.white)),

color: Colors.blue,

)

],

),

),

],

)

)

),

),

),

);

}

}

Kode itu membangun kombinasi widget dari Container, Card, Column, Image, Text, dan RaisedButton. RaisedButtons memiliki acara onPressed yang tindakannya untuk menavigasi ke EditDataWidget dan memicu dialog konfirmasi hapus. Selanjutnya, sebelum penutupan badan kelas _DetailWidgetState, tambahkan metode atau fungsi ini untuk membuka EditDataWidget dengan parameter objek cases.

_navigateToEditScreen (BuildContext context, Cases cases) async {

final result = await Navigator.push(

context,

MaterialPageRoute(builder: (context) => EditDataWidget(cases)),

);

}

Untuk menangani tombol hapus, kita perlu menambahkan metode atau fungsi setelah metode di atas yang menampilkan dialog peringatan untuk mengonfirmasi apakah data akan dihapus.

Future<void> _confirmDialog() async {

return showDialog<void>(

context: context,

barrierDismissible: false, // user must tap button!

builder: (BuildContext context) {

return AlertDialog(

title: Text(‘Warning!’),

content: SingleChildScrollView(

child: ListBody(

children: <Widget>[

Text(‘Are you sure want delete this item?’),

],

),

),

actions: <Widget>[

FlatButton(

child: Text(‘Yes’),

onPressed: () {

api.deleteCase(widget.cases.id);

Navigator.popUntil(context, ModalRoute.withName(Navigator.defaultRouteName));

},

),

FlatButton(

child: const Text(‘No’),

onPressed: () {

Navigator.of(context).pop();

},

),

],

);

},

);

}

Langkah # 6: Tambahkan Data Baru

Kami akan membuat file Dart baru untuk formulir entri untuk menambahkan data baru. Di Form, akan ada TextFieldForm, RadioButton, dan Tombol Kirim. Buat file Dart lib / adddatawidget.dart baru, lalu tambahkan impor ini ke file itu.

import ‘package:flutter/material.dart’;

import ‘package:flutter_restapi/services/api_service.dart’;

import ‘models/cases.dart’;

TextFormField akan menggunakan DateTimeField dan TextEditingController untuk mengikat nilai. Namun untuk Radio Button akan mengikatnya secara manual dengan terlebih dahulu menambahkan variabel enum setelah diimport.

enum Gender { male, female }

enum Status { positive, dead, recovered }

Selanjutnya, buat kelas AddDataWidget yang memperluas StatefulWidget dan memiliki konstruktor serta inisiasi _AddDataWidgetState.

class AddDataWidget extends StatefulWidget {

AddDataWidget();

@override

_AddDataWidgetState createState() => _AddDataWidgetState();

}

Sekarang, buat kelas yang disebut kelas AddDataWidget yang akan membangun tata letak untuk Add data.

class _AddDataWidgetState extends State<AddDataWidget> {

_AddDataWidgetState();

final ApiService api = ApiService();

final _addFormKey = GlobalKey<FormState>();

final _nameController = TextEditingController();

String gender = ‘male’;

Gender _gender = Gender.male;

final _ageController = TextEditingController();

final _addressController = TextEditingController();

final _cityController = TextEditingController();

final _countryController = TextEditingController();

String status = ‘positive’;

Status _status = Status.positive;

@override

Widget build(BuildContext context) {

return Scaffold(

appBar: AppBar(

title: Text(‘Add Cases’),

),

body: Form(

key: _addFormKey,

child: SingleChildScrollView(

child: Container(

padding: EdgeInsets.all(20.0),

child: Card(

child: Container(

padding: EdgeInsets.all(10.0),

width: 440,

child: Column(

children: <Widget>[

Container(

margin: EdgeInsets.fromLTRB(0, 0, 0, 10),

child: Column(

children: <Widget>[

Text(‘Full Name’),

TextFormField(

controller: _nameController,

decoration: const InputDecoration(

hintText: ‘Full Name’,

),

validator: (value) {

if (value.isEmpty) {

return ‘Please enter full name’;

}

return null;

},

onChanged: (value) {},

),

],

),

),

Container(

margin: EdgeInsets.fromLTRB(0, 0, 0, 10),

child: Column(

children: <Widget>[

Text(‘Gender’),

ListTile(

title: const Text(‘Male’),

leading: Radio(

value: Gender.male,

groupValue: _gender,

onChanged: (Gender value) {

setState(() {

_gender = value;

gender = ‘male’;

});

},

),

),

ListTile(

title: const Text(‘Female’),

leading: Radio(

value: Gender.female,

groupValue: _gender,

onChanged: (Gender value) {

setState(() {

_gender = value;

gender = ‘female’;

});

},

),

),

],

),

),

Container(

margin: EdgeInsets.fromLTRB(0, 0, 0, 10),

child: Column(

children: <Widget>[

Text(‘Age’),

TextFormField(

controller: _ageController,

decoration: const InputDecoration(

hintText: ‘Age’,

),

keyboardType: TextInputType.number,

validator: (value) {

if (value.isEmpty) {

return ‘Please enter age’;

}

return null;

},

onChanged: (value) {},

),

],

),

),

Container(

margin: EdgeInsets.fromLTRB(0, 0, 0, 10),

child: Column(

children: <Widget>[

Text(‘Address’),

TextFormField(

controller: _addressController,

decoration: const InputDecoration(

hintText: ‘Address’,

),

validator: (value) {

if (value.isEmpty) {

return ‘Please enter address’;

}

return null;

},

onChanged: (value) {},

),

],

),

),

Container(

margin: EdgeInsets.fromLTRB(0, 0, 0, 10),

child: Column(

children: <Widget>[

Text(‘City’),

TextFormField(

controller: _cityController,

decoration: const InputDecoration(

hintText: ‘City’,

),

validator: (value) {

if (value.isEmpty) {

return ‘Please enter city’;

}

return null;

},

onChanged: (value) {},

),

],

),

),

Container(

margin: EdgeInsets.fromLTRB(0, 0, 0, 10),

child: Column(

children: <Widget>[

Text(‘Country’),

TextFormField(

controller: _countryController,

decoration: const InputDecoration(

hintText: ‘Country’,

),

validator: (value) {

if (value.isEmpty) {

return ‘Please enter country’;

}

return null;

},

onChanged: (value) {},

),

],

),

),

Container(

margin: EdgeInsets.fromLTRB(0, 0, 0, 10),

child: Column(

children: <Widget>[

Text(‘Status’),

ListTile(

title: const Text(‘Positive’),

leading: Radio(

value: Status.positive,

groupValue: _status,

onChanged: (Status value) {

setState(() {

_status = value;

status = ‘positive’;

});

},

),

),

ListTile(

title: const Text(‘Dead’),

leading: Radio(

value: Status.dead,

groupValue: _status,

onChanged: (Status value) {

setState(() {

_status = value;

status = ‘dead’;

});

},

),

),

ListTile(

title: const Text(‘Recovered’),

leading: Radio(

value: Status.recovered,

groupValue: _status,

onChanged: (Status value) {

setState(() {

_status = value;

status = ‘recovered’;

});

},

),

),

],

),

),

Container(

margin: EdgeInsets.fromLTRB(0, 0, 0, 10),

child: Column(

children: <Widget>[

RaisedButton(

splashColor: Colors.red,

onPressed: () {

if (_addFormKey.currentState.validate()) {

_addFormKey.currentState.save();

api.createCase(Cases(name: _nameController.text, gender: gender, age: int.parse(_ageController.text), address: _addressController.text, city: _cityController.text, country: _countryController.text, status: status));

Navigator.pop(context) ;

}

},

child: Text(‘Save’, style: TextStyle(color: Colors.white)),

color: Colors.blue,

)

],

),

),

],

)

)

),

),

),

),

);

}

}

Kelas itu mendeklarasikan semua variabel yang diperlukan yang akan disimpan ke REST API, data binding, inisiasi pembantu database, dan deklarasi Formulir. Formulir tersebut berisi TextFormField, Radio Button, dan Submit Button. Tindakan saat mengirimkan akan menyimpan data ke REST API kemudian dialihkan kembali ke tampilan daftar.

Langkah # 7: Edit Data

Tata letak untuk edit data sama dengan tampilan tambah data dengan parameter objek tambahan yang didapat dari halaman detail. Objek ini akan mengisi nilai default dari TextFormField, Radio Button, dan Submit Button. Saat di submit itu akan mengupdate data berdasarkan ID kemudian redirect ke tampilan daftar. Pertama, buat file dart baru di folder lib lib / edidatawidget.dart. Buka dan edit file itu lalu tambahkan baris kode panah ini untuk membuat formulir edit dan berfungsi untuk mengirimkan formulir ini ke REST API.

import ‘package:flutter/material.dart’;

import ‘package:flutter_restapi/services/api_service.dart’;

import ‘models/cases.dart’;

enum Gender { male, female }

enum Status { positive, dead, recovered }

class EditDataWidget extends StatefulWidget {

EditDataWidget(this.cases);

final Cases cases;

@override

_EditDataWidgetState createState() => _EditDataWidgetState();

}

class _EditDataWidgetState extends State<EditDataWidget> {

_EditDataWidgetState();

final ApiService api = ApiService();

final _addFormKey = GlobalKey<FormState>();

String id = ”;

final _nameController = TextEditingController();

String gender = ‘male’;

Gender _gender = Gender.male;

final _ageController = TextEditingController();

final _addressController = TextEditingController();

final _cityController = TextEditingController();

final _countryController = TextEditingController();

String status = ‘positive’;

Status _status = Status.positive;

@override

void initState() {

id = widget.cases.id;

_nameController.text = widget.cases.name;

gender = widget.cases.gender;

if(widget.cases.gender == ‘male’) {

_gender = Gender.male;

} else {

_gender = Gender.female;

}

_ageController.text = widget.cases.age.toString();

_addressController.text = widget.cases.address;

_cityController.text = widget.cases.city;

_countryController.text = widget.cases.country;

status = widget.cases.status;

if(widget.cases.status == ‘positive’) {

_status = Status.positive;

} else if(widget.cases.status == ‘dead’) {

_status = Status.dead;

} else {

_status = Status.recovered;

}

super.initState();

}

@override

Widget build(BuildContext context) {

return Scaffold(

appBar: AppBar(

title: Text(‘Edit Cases’),

),

body: Form(

key: _addFormKey,

child: SingleChildScrollView(

child: Container(

padding: EdgeInsets.all(20.0),

child: Card(

child: Container(

padding: EdgeInsets.all(10.0),

width: 440,

child: Column(

children: <Widget>[

Container(

margin: EdgeInsets.fromLTRB(0, 0, 0, 10),

child: Column(

children: <Widget>[

Text(‘Full Name’),

TextFormField(

controller: _nameController,

decoration: const InputDecoration(

hintText: ‘Full Name’,

),

validator: (value) {

if (value.isEmpty) {

return ‘Please enter full name’;

}

return null;

},

onChanged: (value) {},

),

],

),

),

Container(

margin: EdgeInsets.fromLTRB(0, 0, 0, 10),

child: Column(

children: <Widget>[

Text(‘Gender’),

ListTile(

title: const Text(‘Male’),

leading: Radio(

value: Gender.male,

groupValue: _gender,

onChanged: (Gender value) {

setState(() {

_gender = value;

gender = ‘male’;

});

},

),

),

ListTile(

title: const Text(‘Female’),

leading: Radio(

value: Gender.female,

groupValue: _gender,

onChanged: (Gender value) {

setState(() {

_gender = value;

gender = ‘female’;

});

},

),

),

],

),

),

Container(

margin: EdgeInsets.fromLTRB(0, 0, 0, 10),

child: Column(

children: <Widget>[

Text(‘Age’),

TextFormField(

controller: _ageController,

decoration: const InputDecoration(

hintText: ‘Age’,

),

keyboardType: TextInputType.number,

validator: (value) {

if (value.isEmpty) {

return ‘Please enter age’;

}

return null;

},

onChanged: (value) {},

),

],

),

),

Container(

margin: EdgeInsets.fromLTRB(0, 0, 0, 10),

child: Column(

children: <Widget>[

Text(‘Address’),

TextFormField(

controller: _addressController,

decoration: const InputDecoration(

hintText: ‘Address’,

),

validator: (value) {

if (value.isEmpty) {

return ‘Please enter address’;

}

return null;

},

onChanged: (value) {},

),

],

),

),

Container(

margin: EdgeInsets.fromLTRB(0, 0, 0, 10),

child: Column(

children: <Widget>[

Text(‘City’),

TextFormField(

controller: _cityController,

decoration: const InputDecoration(

hintText: ‘City’,

),

validator: (value) {

if (value.isEmpty) {

return ‘Please enter city’;

}

return null;

},

onChanged: (value) {},

),

],

),

),

Container(

margin: EdgeInsets.fromLTRB(0, 0, 0, 10),

child: Column(

children: <Widget>[

Text(‘Country’),

TextFormField(

controller: _countryController,

decoration: const InputDecoration(

hintText: ‘Country’,

),

validator: (value) {

if (value.isEmpty) {

return ‘Please enter country’;

}

return null;

},

onChanged: (value) {},

),

],

),

),

Container(

margin: EdgeInsets.fromLTRB(0, 0, 0, 10),

child: Column(

children: <Widget>[

Text(‘Status’),

ListTile(

title: const Text(‘Positive’),

leading: Radio(

value: Status.positive,

groupValue: _status,

onChanged: (Status value) {

setState(() {

_status = value;

status = ‘positive’;

});

},

),

),

ListTile(

title: const Text(‘Dead’),

leading: Radio(

value: Status.dead,

groupValue: _status,

onChanged: (Status value) {

setState(() {

_status = value;

status = ‘dead’;

});

},

),

),

ListTile(

title: const Text(‘Recovered’),

leading: Radio(

value: Status.recovered,

groupValue: _status,

onChanged: (Status value) {

setState(() {

_status = value;

status = ‘recovered’;

});

},

),

),

],

),

),

Container(

margin: EdgeInsets.fromLTRB(0, 0, 0, 10),

child: Column(

children: <Widget>[

RaisedButton(

splashColor: Colors.red,

onPressed: () {

if (_addFormKey.currentState.validate()) {

_addFormKey.currentState.save();

api.updateCases(id, Cases(name: _nameController.text, gender: gender, age: int.parse(_ageController.text), address: _addressController.text, city: _cityController.text, country: _countryController.text, status: status));

Navigator.pop(context) ;

}

},

child: Text(‘Save’, style: TextStyle(color: Colors.white)),

color: Colors.blue,

)

],

),

),

],

)

)

),

),

),

),

);

}

}

Langkah # 8: Jalankan dan Uji Aplikasi Flutter ke Perangkat Android dan iOS

Untuk menjalankan aplikasi Flutter ini ke Android, cukup klik tombol putar di toolbar Android Studio. Pastikan perangkat Android Anda terhubung ke komputer dan muncul di Toolbar Android Studio.

Tutorial Flutter: Menggunakan Aplikasi CRUD REST API Android dan iOS - Toolbar Android Studio

Di sini tampilan aplikasi Flutter yang berfungsi di perangkat Android.

Tutorial Flutter: Menggunakan Aplikasi CRUD REST API Android dan iOS - Android Demo

Untuk menjalankan aplikasi Flutter ini ke perangkat iOS, setidaknya Anda harus memiliki akun pribadi Pengembang Apple dengan domain Anda sendiri (contoh kami: com.djamware) sebagai bundel atau paket. Selanjutnya buka ios / Runner.xcworkspace di XCode lalu klik Runner di Project Navigator.

Tutorial Flutter: Menggunakan Aplikasi CRUD REST API Android dan iOS - Pengaturan XCode

Di Runner.xcodeproj klik tab Build Settings.

Tutorial Flutter: Menggunakan Aplikasi CRUD REST API Android dan iOS - XCode Build Settings

Gulir ke bawah dan temukan Penandatanganan lalu pilih Tim Pengembangan ke akun pribadi Pengembang Apple Anda. Sekarang, Anda dapat menjalankan aplikasi Flutter ke Perangkat iOS dari Xcode atau Android Studio. Berikut tampilan aplikasi Flutter di perangkat iOS.

Tutorial Flutter: Menggunakan Aplikasi CRUD REST API Android dan iOS - Demo iOS

Itu tadi, Tutorial Flutter: Menggunakan Aplikasi CRUD REST API Android dan iOS. Anda bisa mendapatkan kode sumber lengkap dari GitHub kami .

Itu baru dasarnya. Jika Anda membutuhkan pembelajaran yang lebih mendalam tentang Flutter, Dart, atau yang terkait, Anda dapat mengikuti kursus murah berikut ini:

  • Kursus Android Dengan Flutter

Terima kasih!

 

Tinggalkan Balasan

Need Help? Chat with us