HTTP Request Menggunakan Flutter

Tutorial pintar-android.com Http Request menggunakan Flutter

Di tutorial pintar-android.com kali ini kita akan belajar menampilkan list dengan data dari HTTP request menggunakan Flutter. HTTP request yang kita coba buat, akan menembak API yang dibuat dari data Firebase Realtime Database. API tersebut berisi data lirik lagu Jason Mraz yang berjudul “The Woman I Love”. Untuk yang mengikuti tutorial sebelumnya, pasti tahu kalau lagu yang sama juga dipakai untuk belajar membuat model menggunakan Flutter 😀

Mari kita mulai! Download kodingan dari tutorial sebelumnya di https://github.com/meidikawardana/instagram_list . Ekstrak file zip dari project tersebut, lalu rename folder hasil ekstrakan jadi: instagram_list . Buka folder tersebut di Visual Studio Code (VSCode), lalu tekan Ctrl+` (Control + tanda quote) di keyboard untuk membuka terminal di VSCode. lalu ketik di terminal:

flutter pub get

untuk download package flutter supaya project kita bisa jalan.

Sebelum kita menembak API pakai Flutter, kita perlu menyesuaikan sedikit kodingan kita supaya listview yang sudah ada bisa menampilkan data lebih efisien & mengurangi lag ketika di-scroll. Buka file lib/main.dart, lalu cari class InstagramCards. Ubah class InstagramCards sesuai kodingan dibawah ini. Hapus bagian yang dicoret, & tambahkan bagian yang berwarna hijau.

...

class InstagramCards extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    ...

    List<Widget> cards =
        new List.generate(3, (i) => new InstagramCard(instagramPost));

    return ListView(
      children: cards, /*<Widget>[
        InstagramCard()
      ],*/
    );

    return ListView.builder(
      itemBuilder: (BuildContext context, int index) {
        return InstagramCard(instagramPost);
      },
      itemCount: 3,
    );    
  }
}

Setelah itu, kita bisa mulai koding untuk menembak API firebase. Kita perlu menambahkan dulu library untuk menembak API, yaitu library http. Buka file pubspec.yaml, lalu tambahkan baris: http: ^0.12.0+2 di bagian dependencies seperti gambar berikut ini:

gambar  1 - menambahkan library http di pubspec.yaml

Lalu, masih di file main.dart, tambahkan import library http & tambahkan juga fungsi getPosts() untuk mendapatkan data dari API firebase realtime database. Di fungsi getPosts() inilah kita melakukan http request menggunakan Flutter.

...
import 'models/instagram_post.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';

void main() => runApp(AplikasiLikeInstagram());

Future<List<InstagramPost>> getPosts() async {
  final response =
      await http.get('https://instagram-list.firebaseio.com/posts.json');

  if (response.statusCode == 200) {
    final List<InstagramPost> postList = [];
    final Map<String, dynamic> postsJson = json.decode(response.body);

    postsJson.forEach((String id, dynamic data) {
      final InstagramPost product = InstagramPost(
        profilePicture: 'images/insta_profpic.jpg',
        username: 'meidika_wardana',
        picture: data['pic_url'],
        likeCount: int.parse(data['like_count']),
        text: data['text_'],
      );
      postList.add(product);
    });

    return postList;
  } else {
    throw Exception('Gagal menampilkan postingan');
  }
}

class InstagramCards extends StatefulWidget {
   ...

Kalau kita amati, ada beberapa hal yang menarik di fungsi getPosts() di atas. Fungsi getPosts(), biasanya kita sebut sebagai fungsi asynchronous (async) yang menunggu (await) suatu proses. Prosesnya untuk kasus ini adalah menembak API firebase di https://instagram-list.firebaseio.com/posts.json . Proses asynchronous ini, dilakukan di diluar proses utama aplikasi kita (main thread) karena jika dilakukan di main thread, proses async - await bisa memakan waktu yang lama & berpotensi membuat aplikasi kita jadi seakan “hang”.

Fungsi async getPosts(), harus mengembalikan sebuah obyek Future karena fungsi getPosts() akan mengembalikan hasil di waktu yang belum diketahui kapan di masa depan. Hasil fungsi getPosts() adalah sebuah List yang setiap item nya adalah sebuah obyek InstagramPost, atau disingkat List<InstagramPost> .

Nah, sekarang bagaimana kita bisa memanggil fungsi getPosts() ?

Kita akan memanggil fungsi getPosts() di class InstagramCards di file main.dart. Tapi karena fungsi getPosts() berpotensi mengubah tampilan aplikasi, maka kita perlu mengubah class IntagramCards jadi sebuah StatefulWidget. Kalau kita pakai VSCode, ada cara yang cukup mudah untuk mengubah class InstagramCards menjadi StatefulWidget. Klik kanan di class InstagramCards, lalu klik Refactor… seperti gambar berikut ini

gambar 2 - refactoring class InstagramCards

Setelah klik Refactor… , lalu klik “Convert to StatefulWidget”.

gambar 3 - mengubah class InstagramCards menjadi StatefulWidget

Dan class InstagramCards akan berubah jadi StatefulWidget. Akan ada class baru di bawah class InstagramCards, yaitu _InstagramCardsState yang memungkinkan kita mengubah tampilan aplikasi sesuai yang kita mau.

Kembali ke fungsi getPosts, sekarang kita bisa memanggil fungsi getPosts di class _InstagramCardsState. Untuk best practice, kita perlu memanggil getPosts di dalam class _InstagramCardsState, seperti berikut ini:

...

	class InstagramCards extends StatefulWidget {
	  @override
	  _InstagramCardsState createState() => _InstagramCardsState();
	}

	class _InstagramCardsState extends State {
	  Future<List<InstagramPost>> posts;

	  @override
	  void initState() {
		super.initState();
		posts = getPosts();
	  }

	  @override
	  Widget build(BuildContext context) {
		...

Class _InstagramCardsState punya fungsi build() yang dijalankan setiap kali state berubah. Kenapa kita tidak memanggil fungsi getPosts() di fungsi build(), melainkan di fungsi initState() ? Karena fungsi build() akan dipanggil setiap kali tampilan berubah, dan ini akan sangat sering terjadi. Kalau kita panggil fungsi getState() di dalam build(), kita akan menembaki API lebih sering dari yang dibutuhkan, berpotensi membuat aplikasi kita jadi lebih lambat.

Di kodingan di atas, setelah kita panggil fungsi getPosts(), kita mendapatkan obyek posts yang tipenya Future<List<InstagramPost>>. … Ngga perlu takut dengan tipe yang terdengar “asing” dan “rumit” ini ha3… Kalau diterjemahkan, obyek posts cuma bertipe Future yang didalamnya mengandung List berisi InstagramPost.

Sekarang kita bisa pakai obyek posts untuk menampilkan data yang ada didalamnya. Caranya, kita hapus fungsi build() didalam class _InstagramCardsState, lalu copy paste kodingan berikut ini :

...
  @override
  Widget build(BuildContext context) {
    // InstagramPost instagramPost = new InstagramPost(
    //     profilePicture: 'images/insta_profpic.jpg',
    //     username: 'meidika_wardana',
    //     picture: 'https://pintar-android.com/wp_res/insta_pic2.png',
    //     likeCount: 3,
    //     text: 'Lagu romantis dari Jason Mraz :D');

    // return ListView.builder(
    //   itemBuilder: (BuildContext context, int index) {
    //     return InstagramCard(instagramPost);
    //   },
    //   itemCount: 3,
    // );

    return FutureBuilder<List<InstagramPost>>(
      future: posts,
      builder: (context, snapshot) {
        if (snapshot.hasData) {
          return ListView.builder(
            itemBuilder: (BuildContext context, int index) {
              return InstagramCard(snapshot.data[index]);
            },
            itemCount: snapshot.data.length,
          );
        } else if (snapshot.hasError) {
          return Center(
            child: Text(
              "${snapshot.error}",
              textAlign: TextAlign.center,
            ),
          );
        }

        return CircularProgressIndicator();
      },
    );    
  }
  ...

Di kodingan di atas, banyak bagian yang kita komen (//). Bagian itu adalah kodingan asli fungsi build() sebelum kita ubah barusan. Kemudian kita buat supaya fungsi build() mengembalikan sebuah listview dengan menggunakan FutureBuilder. FutureBuilder ini cukup unik. Dia bisa menggunakan obyek posts yang bertipe Future, lalu di bagian builder-nya, kita mendapatkan context dan snapshot. Kita tidak menggunakan context, kita pakai snapshot saja. snapshot ini asalnya dari obyek posts, dan kita bisa mengecek jika snapshot punya data (snapshot.hasData), maka kita menampilkan listview menggunakan data dari snapshot. Kita menampilkan data satu per satu dalam InstagramCard, yang di kodingan di atas ditulis InstagramCard(snapshot.data[index]).

Kita juga bisa mengecek, jika snapshot berisi error (snapshot.hasError), maka kita bisa menampilkan errornya di widget Text.

Di bagian terakhir, kita menampilkan CircularProgressIndicator yang berupa tampilan loading. Tampilan loading ini adalah yang pertama ditampilkan di aplikasi sampai listview ditampilkan (jika snapshot berisi data), atau sampai error ditampilkan (jika snapshot berisi error).

Saatnya kita coba menjalankan aplikasi ini di emulator :D. Kalau tidak ada error, hasilnya akan seperti ini:

gambar 4 - tampilan list dari http request

Tampilan aplikasi di atas, asalnya dari firebase database yang kita ambil menggunakan kodingan2 kita sebelumnya yang cukup panjang di artikel ini. Secara pribadi, penulis sendiri kurang sreg dengan gambar di setiap postingan yang terlalu banyak bagian yang berwarna hitam.

gambar 5 - gambar postingan yang terlalu banyak bagian hitamnya

Kita bisa mengurangi bagian berwarna hitam tersebut, dengan mengeset height (tinggi) container gambar menjadi hanya setinggi gambarnya sendiri. Di file lib/instagram_card.dart, komen 1 baris property height untuk widget Container yang membungkus widget Image.

...
Row(
  //row #2
  children: [
	Expanded(
	  child: Container(
		child: // Image.asset(_instagramPost.picture)
			Image.network(
		  _instagramPost.picture,
		  fit: BoxFit.contain,
		  // height: _screenWidth,
		),
		color: Colors.black,
	  ),
	)
  ],
),
...

Nah.. sekarang kalau kita jalankan lagi, maka bagian warna hitam akan jadi lebih sedikit & menurut penulis, tampilan aplikasi jadi lebih enak dilihat.

gambar 6 - tampilan akhir aplikasi instagram_list

Sampai di sini artikel pintar-android.com kali ini, mengenai http request menggunakan Flutter. Semoga bermanfaat. Kodingan lengkap untuk tutorial ini ada di https://github.com/meidikawardana/instagram_list_http .

Jangan lupa like page pintar-android.com di FB untuk mendapatkan artikel & tutorial lainnya yang pastinya berguna di dunia pemrograman khususnya android.

===============================================================

Tersedia buku-buku untuk belajar pemrograman Android.

Buku pertama, menginstall Android Studio: https://play.google.com/store/books/details?id=EOufCwAAQBAJ .

Buku kedua, membuat recyclerview yang menampilkan gambar2 dari internet menggunakan json: https://play.google.com/store/books/details?id=b-boDAAAQBAJ .

Buku registrasi user, membuat fitur login & register: https://play.google.com/store/books/details?id=FHMqDwAAQBAJ

Buku Onesignal: https://play.google.com/store/books/details?id=4n1oDwAAQBAJ

Menampilkan ListView Dengan Data Dari Model Menggunakan Flutter

menampilkan listview dengan data dari model menggunakan Flutter

Di tutorial kali ini, kita membuat aplikasi yang menampilkan listview dengan data dari model menggunakan Flutter. Aplikasi yang akan kita buat, mirip Instagram yang menampilkan banyak postingan. Postingan2 tersebut akan menampilkan lirik dari lagu Jason Mraz yang berjudul “The Woman I Love”. Sebuah lagu romantis yang disukai penulis he3..

Mari kita mulai! Kita akan mulai koding dari aplikasi yang sudah dibuat di tutorial sebelumnya. Kodingannya bisa didownload di https://github.com/meidikawardana/like_app . Download project tersebut, ekstrak lalu rename folder hasil ekstrakan menjadi “instagram_list”. Kemudian buka folder tersebut di Visual Studio Code (VSCode).

Seharusnya akan ada banyak error di tab “Problems” di kanan bawah, karena file2 package yang dibutuhkan oleh Flutter harus didownload dulu. Jadi buka terminal di VSCode, lalu ketik: flutter pub get .

gambar 1 - jalankan flutter pub get

Setelah semua error hilang, tekan Ctrl+F5 untuk menjalankan project ke emulator. Kalau project berhasil dijalankan di emulator, kita bisa mulai mengubah kodingannya. Buka folder lib di kanan, lalu dobel klik file main.dart untuk membuka file tersebut.

Di file main.dart, ada 2 class yaitu class InstagramCards & class AplikasiLikeInstagram . Kita bisa memindahkan (refactoring) sebagian isi class InstagramCards supaya file main.dart lebih ringkas & lebih mudah dibaca. Buat file baru di dalam folder lib dengan klik kanan di folder lib, lalu pilih “New File”. Lalu beri nama: “instagram_card.dart”. Dobel klik untuk buka file baru tersebut, lalu isi file tersebut dengan kodingan berikut ini:

import 'package:flutter/material.dart';

class InstagramCard extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return null;
  }

}

Lalu kita kembali ke file main.dart. Sorot kodingan pakai mouse, dari baris ke-10 s/d baris ke-120. Kemudian cut kodingan tersebut. Kembali ke file instagram_card.dart, sorot: null di baris ke-6, lalu paste kodingan dari main.dart. Seharusnya akan ada error di baris ke-116 di instagram_card.dart. Hapus koma di baris tersebut supaya errornya hilang. Kemudian tekan Ctrl+S untuk menyimpan file instagram_card.dart. Kalau kesulitan, source nya ada di https://gist.github.com/meidikawardana/c84fab4c24be78fce1f0831b3cf2c61b

Sampai sini, kita sudah memindahkan widget card. Sekarang kita perlu memasukkan widget card tersebut ke class InstagramCards di file main.dart supaya widget card ditampilkan di aplikasi. Kita tinggal “memanggil” class InstagramCard di file main.dart seperti berikut ini:

import 'package:flutter/material.dart';
import 'package:like_app/instagram_card.dart';

void main() => runApp(AplikasiLikeInstagram());

class InstagramCards extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return ListView(
      children: <Widget>[
        InstagramCard()
      ],
    );
  }
}

...

Setelah itu, simpan file main.dart dengan menekan Ctrl+S. Seharusnya tampilan di aplikasi akan sama dengan sebelum kita memindah kodingan card.

Saat ini, card berisi postingan yang ditampilkan di aplikasi hanya ada 1 buah. Kita bisa dengan mudah menampilkan lebih dari 1 card. Kita tinggal menambahkan beberapa card dengan metode looping. Ubah class InstagramCards di main.dart jadi seperti ini:

class InstagramCards extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    List<Widget> cards = new List.generate(3, (i) => new InstagramCard());

    return ListView(
      children: cards,  /*<Widget>[
        InstagramCard()
      ],*/ 
    );
  }
}

Yang berwarna biru di kodingan di atas, adalah untuk membuat beberapa card menggunakan looping (perintah List.generate()), lalu membuat hasilnya (variabel cards) menjadi anak (children) dari widget ListView. Sedangkan kodingan sebelumnya berwarna merah yang menampilkan hanya 1 card, kita komen dengan tanda /* di sebelum dan tanda */ di sesudahnya. Coba jalankan lagi ke emulator dengan Ctrl+F5, maka akan tampil 3 card berisi postingan mirip instagram 😀

Saat ini, card hanya menampilkan teks dan gambar yang kita tulis di kodingan class InstagramCard. Kita perlu membuat supaya card menampilkan data dari sebuah class model, supaya nantinya kita bisa mengubah2 data yang ditampilkan dengan lebih mudah. Buat 1 folder baru di folder lib di sebelah kanan, dan beri nama “models” untuk folder baru tersebut. Di dalam folder “models”, buat file “instagram_post.dart” yang berisi class model yang kita perlukan.

gambar 1b - membuat file instagram_post.dart di folder models

Isi file “instagram_post.dart” adalah seperti berikut ini:

import 'package:flutter/material.dart';

class InstagramPost {
  final String profilePicture;
  final String username;
  final String picture;
  final int likeCount;
  final String text;

  InstagramPost(
      {@required this.profilePicture,
      @required this.username,
      @required this.picture,
      @required this.likeCount,
      @required this.text});
}

Struktur folder project kita akan seperti ini:

gambar 2 - struktur project listview flutter

Setelah kita membuat class model, kita bisa menggunakan class model tersebut untuk menampilkan data. Di file main.dart, kita bisa memanggil class tersebut, membuat sebuah obyek menggunakan model tersebut, lalu memasukkan obyek tersebut ke card supaya ditampilkan di card. Ubah kodingan main.dart jadi seperti berikut ini:

import 'package:flutter/material.dart';
import 'package:like_app/instagram_card.dart';

import 'models/instagram_post.dart';

void main() => runApp(AplikasiLikeInstagram());

class InstagramCards extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    InstagramPost instagramPost = new InstagramPost(
        profilePicture: 'images/insta_profpic.jpg',
        username: 'meidika_wardana',
        picture: 'images/insta_pic.jpg',
        likeCount: 1,
        text:
            'Lagi lucu2nya nih ... he3. Semoga jadi anak yang berbakti ke ortu :D');

    List<Widget> cards =
        new List.generate(3, (i) => new InstagramCard(instagramPost));

    return ListView(
      children: cards, /*<Widget>[
        InstagramCard()
      ],*/
    );
  }
}

...

Di kodingan di atas, di warna biru kita mengimport file instagram_post.dart ke file main.dart supaya kita bisa menggunakan class InstagramPost. Di warna hijau, kita membuat sebuah obyek menggunakan class InstagramPost. Obyek ini berisi data yang bisa tampilkan di sebuah card. Setelah kita membuat obyek tersebut, kita memasukkan obyek tersebut ke InstagramCard.

Saat ini kodingan kita akan error karena class InstagramCard perlu kita ubah supaya bisa menerima obyek InstagramPost. Jadi buka file instagram_card.dart, lalu ubah isinya jadi seperti berikut ini:

import 'package:flutter/material.dart';

import 'models/instagram_post.dart';

class InstagramCard extends StatelessWidget {

  final InstagramPost _instagramPost;

  InstagramCard(this._instagramPost);

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Row(
          // row #1
          children: [
            Container(
              child: Image.asset(
                _instagramPost.profilePicture,
                width: 30,
                fit: BoxFit.contain,
              ),
              margin: EdgeInsets.all(10),
            ),
            Expanded(
              child: Text(
                _instagramPost.username,
                style: TextStyle(
                  fontWeight: FontWeight.bold,
                ),
              ),
            ),
            IconButton(
              icon: Icon(Icons.more_vert),
              onPressed: () {},
            )
          ],
        ),
        Row(
          //row #2
          children: <Widget>[
            Expanded(
              child: Image.asset(_instagramPost.picture),
            )
          ],
        ),
        Row(
          //row #3
          children: <Widget>[
            IconButton(
              icon: Image.asset(
                'images/ic_love.png',
                fit: BoxFit.contain,
              ),
              onPressed: () {},
            ),
            IconButton(
              icon: Image.asset(
                'images/ic_comment.png',
                fit: BoxFit.contain,
              ),
              onPressed: () {},
            ),
            IconButton(
              icon: Image.asset(
                'images/ic_send.png',
                fit: BoxFit.contain,
              ),
              onPressed: () {},
            ),
            Expanded(
              child: IconButton(
                icon: Image.asset(
                  'images/ic_save.png',
                  fit: BoxFit.contain,
                ),
                onPressed: () {},
                padding: EdgeInsets.only(right: 10),
                alignment: Alignment.centerRight,
              ),
            ),
          ],
        ),
        Row(
          //row #4
          children: <Widget>[
            Container(
              child: Text(
                _instagramPost.likeCount.toString() + ' like',
                style: TextStyle(fontWeight: FontWeight.bold),
              ),
              padding: EdgeInsets.only(left: 10),
            ),
          ],
        ),
        Row(
          //row #5
          children: <Widget>[
            Container(
              child: RichText(
                text: new TextSpan(
                  style: new TextStyle(
                    fontSize: 14.0,
                    color: Colors.black,
                  ),
                  children: <TextSpan>[
                    TextSpan(
                        text: _instagramPost.username + ' ',
                        style: new TextStyle(fontWeight: FontWeight.bold)),
                    TextSpan(text: _instagramPost.text),
                  ],
                ),
              ),
              padding: EdgeInsets.only(left: 10, top: 5, bottom: 10),
              width: MediaQuery.of(context).size.width * 0.8,
            )
          ],
        ),
      ],
    );
  }
}

Di kodingan di atas, di warna biru kita mengimport file instagram_post supaya kita bisa menggunakan class InstagramPost di file instagram_card.dart. Kemudian di warna hijau, kita membuat sebuah obyek InstagramPost, dan menggunakan obyek tersebut supaya class InstagramCard bisa menerima obyek InstagramPost di file main.dart. Kita menerima obyek tersebut di fungsi yang biasa disebut constructor. Nah, setelah obyek tersebut diterima, kita bisa menggunakan obyek tersebut untuk menampilkan data2 di card, yang di kodingan di atas berwarna merah. Cukup banyak data yang perlu ditampilkan mulai dari gambar profile (profile picture) sampai teks postingan yang ada di card. Kalau kita jalankan lagi ke emulator, maka tampilan aplikasi masih sama, menampilkan 3 postingan seperti sebelumnya.

gambar 3 - tampilan aplikasi flutter pakai listview

Karena kita sudah memisahkan class InstagramCard jadi file tersendiri dari main.dart, kita bisa lebih mudah mengubah-ubah tampilan card. Kita tinggal mengubah class InstagramCard, maka tampilan semua card akan berubah. Misal kita mau mengubah gambar postingan, dari yang sekarang dimuat dari gambar di folder images, menjadi gambar yang dimuat dari internet. Maka kita tinggal mengubah class InstagramCard seperti berikut ini.

    ...
    Row( //file instagram_card.dart sekitar baris ke-39
      //row #2
      children: <Widget>[
        Expanded(
          child:
              // Image.asset(_instagramPost.picture)
              Image.network(_instagramPost.picture),
        )
      ],
    ),
    ...

Intinya kita tinggal mengubah dari Image.asset() jadi Image.network(). Cuma, kalau kita coba lagi jalankan aplikasi ke emulator, maka gambarnya tidak muncul dan di tab “debug console” di bagian bawah akan ada banyak error. Karena kita mencoba untuk memuat gambar dari variabel _instagramPost.picture, yang isinya adalah “images/insta_pic.jpg” (bisa dilihat di file main.dart sekitar baris ke-14). Padahal, kalau kita pakai Image.network(), maka kita harus memuat gambar dari sebuah link url.

Maka sekarang kita perlu mengubah obyek InstagramPost sesuai kebutuhan. Coba ubah obyek InstagramPost di file main.dart jadi seperti berikut ini:

	...
  @override //file main.dart sekitar baris ke-10
  Widget build(BuildContext context) {
    InstagramPost instagramPost = new InstagramPost(
        profilePicture: 'images/insta_profpic.jpg',
        username: 'meidika_wardana',
        picture:  'https://pintar-android.com/wp_res/insta_pic2.png',
        likeCount: 3,
        text: 'Lagu romantis dari Jason Mraz :D');


    List<Widget> cards =
        new List.generate(3, (i) => new InstagramCard(instagramPost));
	...

Nah.. sekarang kita bisa coba jalankan lagi aplikasi ke emulator dengan Ctrl+F5. Tapi ada kemungkinan aplikasi masih belum menampilkan gambar. Jadi kita kita bisa stop aplikasi dengan menekan tombol stop di VSCode, lalu tekan lagi Ctrl+F5. Maka aplikasi akan menampilkan gambar & isi card sesuai yang kita ubah di InstagramPost barusan.

gambar 4 - tampilan aplikasi dengan gambar baru

Dengan membuat obyek InstagramPost, kita lebih mudah mengubah isi card termasuk gambar yang dimuat. Jadi ngga percuma, kan, kita buat obyek InstagramPost? He3..

Tutorial kali ini sudah bisa dianggap selesai, tapi ada 1 hal kecil yang kurang. Kalau diperhatikan, postingan di aplikasi Instagram asli selalu memuat gambar yang ukurannya kotak sempurna (bujursangkar), kan? Nah, di aplikasi kita, ternyata tampilan gambar masih menyesuaikan ukuran asli gambar tersebut, & belum tentu kotak sempurna. Untuk memperbaiki ini, caranya cukup mudah. Tinggal ubah di file instagram_card.dart, class InstagramCard, lalu tambahkan kodingan seperti berikut ini.

...

class InstagramCard extends StatelessWidget {
  final InstagramPost _instagramPost;

  InstagramCard(this._instagramPost);

  @override
  Widget build(BuildContext context) {
    double _screenWidth = MediaQuery.of(context).size.width;

    return Column(
		...
        Row(
          //row #2
          children: [
            Expanded(
              child: Container(
                child:  // Image.asset(_instagramPost.picture)
                    Image.network(
                  _instagramPost.picture,
                  fit: BoxFit.contain,
                  height: _screenWidth,
                ),
                color: Colors.black,
              ),
            )
          ],
        ),
		...

Coba jalankan lagi aplikasinya ke emulator, maka tampilannya akan lebih mirip Instagram.

gambar 5 - aplikasi yang menampilkan listview dengan data dari model menggunakan Flutter sudah selesai

Secara pribadi, saya lebih suka tampilan sebelumnya. Tapi karena kali ini kita mau bikin aplikasi yang semirip mungkin dengan Instagram, maka kita perlu ubah sedikit hal kecil tadi 🙂 .

Kodingan lengkap untuk tutorial ini ada di https://github.com/meidikawardana/instagram_list .

Demikian tutorial kali ini, mengenai menampilkan listview dengan data dari model menggunakan Flutter. Semoga bermanfaat dan jangan lupa like page pintar-android.com di FB untuk mendapatkan artikel & tutorial lainnya yang pastinya berguna di dunia pemrograman khususnya android.

===============================================================

Tersedia buku-buku untuk belajar pemrograman Android.

Buku pertama, menginstall Android Studio: https://play.google.com/store/books/details?id=EOufCwAAQBAJ .

Buku kedua, membuat recyclerview yang menampilkan gambar2 dari internet menggunakan json: https://play.google.com/store/books/details?id=b-boDAAAQBAJ .

Buku registrasi user, membuat fitur login & register: https://play.google.com/store/books/details?id=FHMqDwAAQBAJ

Buku Onesignal: https://play.google.com/store/books/details?id=4n1oDwAAQBAJ

Membuat Fitur Like Mirip Instagram Pakai Flutter

Di tutorial kali ini, kita akan membuat fitur like mirip Instagram pakai Flutter. Di tutorial sebelumnya, kita sudah membuat tampilan mirip Instagram menggunakan Flutter di Visual Studio Code (VSCode). Di tutorial kali ini, kita akan menambahkan sedikit fitur supaya kita bisa menekan tombol like seperti di aplikasi Instagram. Mari kita mulai 😀

Kodingan lengkap artikel sebelumnya ada di https://github.com/meidikawardana/like_app . Untuk yang ingin melihat hanya file2 utamanya saja, ada di gist di sini. Di gist tersebut hanya ada main.dart & pubspec.yaml saja.

Kodingan kita yang terakhir terdiri dari 2 class, yaitu class AplikasiLikeInstagram (utama) dan class InstagramCards yang menampilkan 1 postingan mirip Instagram. Di class InstagramCards kita sudah membuat beberapa tombol menggunakan widget IconButton. Salah satu tombol tersebut, adalah tombol Like berbentuk hati. Saat ini, tombol tersebut tidak aktif. Tidak akan terjadi apa-apa kalau kita menekan tombol tersebut. Nah, di tutorial kali ini kita akan membuat supaya tombol tersebut bisa berfungsi & mengubah jumlah like di postingan terkait.

Supaya tombol like bisa berfungsi, kita perlu mengubah class InstagramCards supaya menjadi turunan dari StatefulWidget. Sebelum itu, kita perlu memindah isi dari class InstagramCards ke sebuah class baru, supaya kodingan kita lebih rapi. Di bawah class InstagramCards, buat class _InstagramCardsState

class _InstagramCardsState {
  
}

Kemudian, pindahkan semua yang ada di dalam class InstagramCards, dari setelah kurung kurawal buka sampai sebelum kurung kurawal tutup ke class _InstagramCardsState . Kondisi 2 class tersebut, sekarang jadi seperti ini:

class InstagramCards extends StatelessWidget {

}

class _InstagramCardsState {
  
  @override
  Widget build(BuildContext context) {
    return ListView(
      children: <Widget>[
          ... // kodingan lengkap disingkat supaya lebih mudah dimengerti
      ],
    );
  }
}

Class InstagramCards sekarang jadi error (bergaris keriting merah), tapi kita akan betulkan. Jangan takut error, karena error bisa mempercepat kita mengerti he3..

gambar  1 - class InstagramCards error

Sekarang, ubah class InstagramCards jadi seperti ini:

class InstagramCards extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return _InstagramCardsState();
  }
}

Artinya, InstagramCards sekarang jadi turunan dari StatefulWidget. Yaitu widget yang memungkinkan kita mengubah tampilan di aplikasi tanpa perlu pindah halaman. Di dalam StatefulWidget, kita bisa menulis logika yang kita mau, dan logika tersebut akan bisa mengubah tampilan aplikasi tanpa kita perlu pindah halaman.

gambar  2 - error ketika memanggil class _InstagramCardsState

Sekarang ada error ketika kita memanggil class _InstagramCardsState (di baris 8 pada gambar di atas). Supaya tidak error, kita perlu membuat _InstagramCardsState menjadi turunan dari class State yang disediakan Flutter. Kodingannya hanya perlu diubah sedikit:

gambar 3 - class _InstagramCardsState mengextend State

Setelah kita tambahkan kodingan extends State<InstagramCards> pada class _InstagramCardsState seperti pada gambar di atas, maka kita bisa menambahkan logika supaya tombol like bisa berfungsi. Kita bisa menambahkan variabel untuk menampung jumlah like, & variabel untuk menentukan apakah postingan sudah kita like atau belum. Misal kita namakan variabel _jumlahLike & _sudahLike, & kita taruh di class _InstagramCardsState seperti berikut ini.

gambar 4 - menambahkan 2 variabel

Kemudian pada tombol Like, kita tambahkan kodingan di dalam fungsi onPressed nya. Seperti ini:

                IconButton(
                  icon: Image.asset(
                    'images/ic_love.png',
                    fit: BoxFit.contain,
                  ),
                  onPressed: () {
                    if (!_sudahLike) {
                      setState(() {
                        _jumlahLike += 1;
                        _sudahLike = true;
                      });
                    } else {
                      setState(() {
                        _jumlahLike -= 1;
                        _sudahLike = false;
                      });
                    }
                  },
                ),

Kodingan yang kita tambahkan di atas, artinya jika _sudahLike = false maka kita set nilai variabel _jumlahLike jadi ditambah 1, dan _sudahLike = true. Kalau _sudahLike = true maka kita set kebalikannya. _jumlahLike jadi dikurangi 1, dan _sudahLike jadi false. Kita mengeset variabel2 tersebut, di dalam sebuah fungsi yang disediakan Flutter yaitu setState.

Kalau kita sudah melibatkan fungsi setState di aplikasi kita, maka seringnya fitur hot reload Flutter tidak berfungsi. Karena itu, jika kita ingin mencoba kodingan yang barusan, maka kita perlu restart aplikasi di emulator dengan menekan Ctrl+Shift+F5 di Visual Studio Code (VSCode) jika menggunakan OS Windows.

Setelah aplikasi berjalan di emulator, & kita coba, ternyata tombol Like belum berfungsi. Kenapa? karena kita baru mengubah variabel di state nya saja. Sedangkan kita belum mengubah tampilan tombol like & tulisan jumlah like. Ubah kodingan tombol like, dari seperti ini:

                IconButton(
                  icon: Image.asset(
                    'images/ic_love.png',
                    fit: BoxFit.contain,
                  ),
                  onPressed: () {
                     // ... dipersingkat supaya lebih mudah dimengerti
                  },
                ),

Menjadi seperti ini:

                IconButton(
                  icon: (!_sudahLike)
                      ? Icon(
                          Icons.favorite_border,
                          color: Colors.grey,
                          size: 32.0,
                        )
                      : Icon(
                          Icons.favorite,
                          color: Colors.red,
                          size: 32.0,
                        ),
                  onPressed: () {
                     // ... dipersingkat supaya lebih mudah dimengerti
                  },
                ),

Artinya, kita mengubah ikon tombol like, supaya kalau belum like (_sudahLike = false) maka kita tampilkan ikon Icons.favorite_border warna abu-abu. Sedangkan kalau sudah like, maka kita tampilkan ikon Icons.favorite warna merah.

Setelah itu, kita ubah tulisan jumlah like di row #4 sesuai variabel _jumlahLike. Penjelasan row #4 ada di artikel minggu lalu . Ubah kodingan row #4 jadi seperti ini:

            Row(
              //row #4
              children: [
                Container(
                  child: Text(
                    _jumlahLike.toString() + ' like',
                    style: TextStyle(fontWeight: FontWeight.bold),
                  ),
                  padding: EdgeInsets.only(left: 10),
                ),
              ],
            ),

Nah, sekarang kalau kita coba jalankan lagi aplikasi kita di emulator, maka jadinya seperti ini:

Tombol Like sudah aktif. Dan dengan membuat tombol like ini, kita sudah belajar beberapa hal mengenai Flutter, antara lain StatefulWidget, tipe variabel, if – else, dan alur logika di Flutter. Lumayan kan? he3..

Kodingan lengkap untuk tutorial kali ini, bisa dilihat di https://github.com/meidikawardana/like_app/tree/stateful_widget .

Sampai di sini tutorial mengenai membuat fitur like mirip Instagram pakai Flutter, semoga bermanfaat dan jangan lupa like page pintar-android.com di FB untuk mendapatkan artikel & tutorial lainnya yang pastinya berguna di dunia pemrograman khususnya android.

===============================================================

Tersedia buku-buku untuk belajar pemrograman Android.

Buku pertama, menginstall Android Studio: https://play.google.com/store/books/details?id=EOufCwAAQBAJ .

Buku kedua, membuat recyclerview yang menampilkan gambar2 dari internet menggunakan json: https://play.google.com/store/books/details?id=b-boDAAAQBAJ .

Buku registrasi user, membuat fitur login & register: https://play.google.com/store/books/details?id=FHMqDwAAQBAJ

Buku Onesignal: https://play.google.com/store/books/details?id=4n1oDwAAQBAJ