Pendahuluan
Carousel atau sebuah Slide Show memang menarik selalu menarik apabila terdapat pada sebuah layout, karena selain fungsinya minimalis tapi bisa menyampaikan banyak informasi karena adanya objek yang saling bergantian untuk ditampilkan. Fitur ini biasanya banyak digunakan untuk menampilkan informasi penting ataupun promosi agar segera dilihat oleh pengguna aplikasi.
Berbeda halnya jika anda adalah seorang web developer, maka tidak asing lagi dengan carousel milik Bootstrap dimana class-nya bisa langsung digunakan tanpa perlu membuatnya secara manual. Flutter sendiri memiliki banyak package atau library untuk mewujudkan hal tersebut, akan tetapi pada artikel kali ini kita akan belajar membuat Carouse Slide Show dengan List View dan Page View secara manual.
Adapun hasil yang akan dicapai akan terlihat seperti video berikut.
Baca Juga: Mengenal Widget Flutter #7: Membuat UI Profile Instagram
Install Flutter & Kerangka Dasar Layout
Sebelum memulai mengerjakan project yang diinginkan, maka install Flutter terlebih dahulu dengan command.
flutter create dw_carousel
Buka file Flutter yang baru saja di-install, kemudian modifikasi file lib/main.dart
menjadi
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Home(),
);
}
}
class Home extends StatefulWidget {
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
//KOMENTAR-INISIASI-VARIABLE
@override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Column(
children: <Widget>[
Flexible(
flex: 1,
child: Container(
margin: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
//KOMENTAR-1 PROFILE AREA
//KOMENTAR-2 DESCRIPTION
//KOMENTAR-3 LISTVIEW CAROUSEL
//KOMENTAR-4 INFORMATION
],
),
),
),
Flexible(
flex: 1,
child: Container(
color: Colors.white,
child: Column(
children: <Widget>[
//KOMENTAR-5 ACTUALLY CATEGORY TAB
Divider(),
//KOMENTAR-6 CAROUSEL PAGE VIEW
],
),
),
),
],
),
),
);
}
//KOMENTAR-PARTIAL-WIDGET
}
Note: Kode di atas sudah dilengkapi dengan komentar sebagai penanda untuk kemudian nantinya akan di-replace dengan code lainnya sesuai dengan fungsinya masing-masing. Jadi apabila selama penulisan selanjutnya disebutkan kode komentar di atas, maka replace dengan code yang baru.
Adapun penjelasan mengenai Flexible, Container dan lain sebagainya bisa ditemukan pada artikel seri Mengenal widget flutter sebelumnya.
Bagian pertama yang akan kita selesaikan adalah KOMENTAR-1 untuk profile area, tambahkan code berikut untuk menampilkan profile yang terdiri dari gambar, nama, company/organisasi, dan tombol menu pada pojok paling kanan.
//KOMENTAR-1
profileArea(),
Kok code-nya cuman sebaris? Yap, karena selengkapnya kita pisahkan ke dalam fungsi tersediri agar lebih memudahkan untuk mengelolanya. Tambahkan block code di bawah ini pada area KOMENTAR-PARTIAL-WIDGET.
profileArea() {
//KITA MENGGUNAKAN ROW KARENA TERDIRI DARI 3 BAGIAN SECARA HORIZONTAL
//GAMBAR - NAME/COMPANY - MENU
return Row(
children: <Widget>[
//GAMBAR UNTUK PROFILENYA KITA SET SEBUAH CONTAINER DENGAN UKURAN 50
Container(
width: 50,
height: 50,
margin: EdgeInsets.only(right: 10),
//DAN GAMBARNYA DIBUNGKUS DGN CLIPRRECT
child: ClipRRect(
//DENGAN BORDER RADIUS SETENGAH DARI UKURAN CONTAINER AGAR MEMBENTUK LINGKARAN
borderRadius: BorderRadius.circular(25),
//GAMBARNYA DI-LOAD DARI INTERNET, DALAM HAL INI LOGO DAENGWEB
child: Image.network(
'https://daengweb.id/front/d-blog/img/favicon.png',
fit: BoxFit.cover, //AGAR MEMENUHI SELURUH AREA CONTAINER
),
),
),
//PADA BAGIAN KEDUA BERISI NAMA DAN COMPANY/ORGANIZATION
//KARENA BERTUMPUK SECARA VERTICAL, MAKA KITA MASUKKAN KEDALAM COLUMN
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Anugrah Sandi',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
),
Text('Daengweb.id')
],
),
//DIANTAR ICON DAN IMAGE/NAME KITA GUNAKAN SPACE DGN FLEX 2 AGAR MENU ICON TERSEBUT BERADA PADA POSISI PALING KANAN
Spacer(
flex: 2,
),
Icon(
Icons.menu,
size: 50,
)
],
);
}
Kemudian bagian lainnya adalah deskripsi dari profile user, replace KOMENTAR-2 dengan baris code berikut.
//KOMENTAR-2
Padding(
padding: const EdgeInsets.only(top: 15.0),
child: Text(
'Discover',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.bold,
),
),
),
Text(
'Live with no excuses and travel with no regrets, Oscar Wild',
style: TextStyle(
fontSize: 15,
fontStyle: FontStyle.italic,
),
),
Note: Tidak ada yang perlu dijelaskan karena hanya sebuah teks.
Membuat Carousel Dengan List View
Cara paling mudah membuat carousel adalah dengan menggunakan widget yang sudah pernah dikelakan sebelumnya, yakni List View. Widget ini memiliki sebuah attribute untuk menentukan arah scroll-nya baik secara vertical maupun horizontal. Adapun bagian yang akan dikerjakan dengan menggunakan List View ini adalah carousel untuk favorite places.
Replace code untuk KOMENTAR-3 dengan block code di bawah ini
//KOMENTAR-3
//HANYA SEBUAH TEKS UNTUK LABEL
Padding(
padding: EdgeInsets.only(top: 10, bottom: 10),
child: Text(
'Favorite Places',
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 20),
),
),
Container(
//KETIKA MENGGUNAKAN LIST VIEW DI DALAM COLUMN, MAKA WRAP DIA DENGAN EXPANDED UNTUK MENGHINDARI ERROR
child: Expanded(
//KITA MENGGUNAKAN SEPARATED UNTUK MEMBUAT SEPARATOR ANTAR CAROUSEL
child: ListView.separated(
physics: PageScrollPhysics(),
//ADAPUN SEPARATORNYA MENGGUNAKAN DIVIDER DENGAN INDENT 3
//INDENT AKAN MEMBUAT JARAK SESUAI VALUE YANG DIMILIKINYA
separatorBuilder: (context, index) => Divider(
indent: 3,
),
scrollDirection: Axis.horizontal, //ATUR ARAH SCROLLNYA SECARA HORIZONTAL
itemCount: _favoriteImage.length, //ADAPUN JUMLAH ITEMNYA TERGANTUNG BERAPA BANYAK DATA YANG ADA DI VARIABLE _favoriteImage
//BUILDERNYA AKAN MEMUAT SEBUAH FUNGSI BARU YANG BERISI WIDGET UNTUK MENAMPILKAN CONTENT
itemBuilder: (context, index) => favoritePlace(index),
),
),
),
Note: Content-nya dipisahkan pada fungsi baru agar tidak menumpuk di dalam satu block code.
Tambahkan code berikut setelah fungsi profileArea()
favoritePlace(index) {
//PER-CONTENT SLIDENYA KITA TENTUKAN UKURANNYA DENGAN SIZEDBOX
return SizedBox(
height: 80, //DIMANA TINGGINYA 80
width: 250, //DAN LEBARNYA 250
child: Container(
//KEMUDIAN SET MARGIN DAN PADDINGNYA AGAR TIDAK MERAPAT PADA OBJEK LAINNYA
margin: EdgeInsets.only(right: 10),
padding: EdgeInsets.only(left: 10, top: 10, bottom: 10),
//KEMUDIAN CONTAINER INI KITA BUAT GARIS BORDER DISEKELILINGNYA
decoration: BoxDecoration(
//DENGAN KETEBALAN 0.3 DAN WARNA GREY
border: Border.all(width: 0.3, color: Colors.grey),
//DAN KEEMPAT SISINYA DIBUAT MELENGKUNG
borderRadius: BorderRadius.circular(10)),
//ADAPUN CONTENTNYA TERDIRI DARI 2 BAGIAN, YAKNI GAMBAR DAN INFORMASI
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
//BAGIAN GAMBARNYA SEPERTI BIASA MENGGUNAKAN CONTAINER DENGAN IMAGE YANG MENUTUPINYA
Container(
height: 60,
width: 60,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
image: DecorationImage(
//IMAGENYA KITA AMBIL DARI VARIABLE _FAVORITEIMAGE DENGAN INDEX SESUAI DENGAN LOOPING DARI LIST VIEW
image: AssetImage(
_favoriteImage[index]['image'],
),
//SET BAGIAN INI AKAN IMAGE MENUTUPI SEPENUHNYA
fit: BoxFit.cover,
),
),
),
//BAGIAN KEDUA ADALAH INFORMASI YANG TERDIRI DARI 3 BAGIAN
//NAMA TEMPAT, CATEGORY DAN JAM KERJA
Padding(
padding: const EdgeInsets.only(left: 8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
_favoriteImage[index]['name'],
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(
_favoriteImage[index]['cat'],
style: TextStyle(fontSize: 12, color: Colors.grey),
),
Text(
_favoriteImage[index]['open'],
style: TextStyle(fontSize: 12, color: Colors.grey),
),
],
),
)
],
),
),
);
}
Terus variable untuk data image-nya bagaimana? Masih ingat dengan code KOMENTAR-INISIASI-VARIABLE? Masukkan code berikut ini di dalamnya
final _favoriteImage = {
{
'name': 'Bantimurung',
'image': 'images/bantimurung.jpg',
'cat': 'Air Terjun',
'open': '09.00-17.00 WITA'
},
{
'name': 'Pantai Bira',
'image': 'images/bira.jpg',
'cat': 'Wisata Bahari',
'open': '06.00-21.00 WITA'
},
{
'name': 'Malino',
'image': 'images/malino.jpg',
'cat': 'Wisata Alam',
'open': '09.00-17.00 WITA'
},
{
'name': 'Pantai Losari',
'image': 'images/pantai-losari.jpg',
'cat': 'Landmark',
'open': '06.00-17.00 WITA'
},
{
'name': 'Tana Toraja',
'image': 'images/toraja.jpg',
'cat': 'Wisata Budaya',
'open': '9.00-17.00 WITA'
},
}.toList();
Tugas terakhir adalah me-register ke-5 image tersebut karena sifatnya adalah local file. Download seluruh file-nya di repository artikel ini dan simpan di dalam folder images
di root directory (red: jika folder images belum ada, silahkan buat foldernya).
Modifikasi file pubspec.yaml
menjadi.
assets:
- images/bantimurung.jpg
- images/bira.jpg
- images/malino.jpg
- images/pantai-losari.jpg
- images/toraja.jpg
Sebagai penutup dari section ini adalah menampilkan kotak informasi, replace code KOMENTAR-4 dengan code berikut.
//KOMENTAR-4
Container(
margin: const EdgeInsets.only(top: 10),
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
border: Border.all(width: 0.5, color: Colors.grey),
borderRadius: BorderRadius.circular(20),
),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(right: 8.0),
child: Icon(
Icons.info_outline,
color: Colors.red,
),
),
Text(
'Informasi',
style: TextStyle(
fontWeight: FontWeight.bold, fontSize: 20),
)
],
),
Divider(),
Padding(
padding: const EdgeInsets.only(
top: 8.0, left: 8, bottom: 5),
child: Text(
'Jangan membuang sampah sekecil apapun selama berada dilokasi pariwisata, cagar budaya dan cagar alam adalah miliki bersama, maka lestarikanlah.',
style: TextStyle(color: Colors.grey),
),
)
],
),
)
Note: Penjelasan dari code di atas hanya mengulang kegiatan sebelumnya yakni membuat sebuah kotak dengan border berwarna grey dan setiap sudutnya dibuat melengkung. Adapun content-nya adalah teks informasi yang ingin disampaikan.
Membuat Carousel Dengan Page View
Teknik lainnya dalam membuat carousel atau image slide show dengan Flutter adalah menggunakan widget PageView. Widget tersebut belum pernah dibahas sebelumnya maka akan menjadi materi baru dalam artikel ini.
Sebelum membuat carousel-nya, maka bagian pertama adalah menampilkan 3 buah teks untuk kategori dimana seharusnya adalah tab tapi karena saya tidak punya ide untuk content pada tab berikutnya maka kita buat hanya dalam bentuk teks biasa saja.
Replace KOMENTAR-5 dengan code berikut
//KOMENTAR-5
Padding(
padding: const EdgeInsets.only(top: 10, bottom: 10),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Row(
children: <Widget>[
Text('Wisata Alam', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14),),
Icon(Icons.check_circle, color: Colors.red,)
],
),
Text('Wisata Budaya', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14),),
Text('Wisata Kuliner', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14),),
],
),
),
Note: Hanya menampilkan teks biasa jadi tidak perlu penjelasan.
Tiba saatnya untuk membuat carousel di Flutter menggunakan PageView, replace KOMENTAR-6
//KOMENTAR-6
Expanded(
//MENGGUNAKAN BUILDER
child: PageView.builder(
//DIMANA CONTROLLERNYA DIAMBIL DARI VARIABLE _PAGECONTROLLER YANG AKAN DIBUAT NANTI
controller: _pageController,
//KETIKA PAGENYA BERGANTI ATAU CAROUSELNYA DIGESER
onPageChanged: (value) {
setState(() {
//MAKA CURRENT SLIDE DIUBAH VALUENYA
_currentSlide = value;
});
},
//ITEM BUILDERNYA MEMUAT FUNGSI BARU BERNAMA slideShow DENGAN MENGIRIMKAN INDEX LOOPING DARI PAGEVIEW
itemBuilder: (BuildContext context, int index) =>
slideShow(index),
//JUMLAH SLIDENYA KITA SET 3 SAJA
itemCount: 3,
),
),
Kemudian tambahkan code di bawah ini setelah fungsi favoritePlace()
slideShow(int index) {
//CONTENTNYA ADALAH SEBUAH CONTAINER
return Container(
//YANG SUDAH DI-SET MARGIN DISEKELILINGNYA
margin: EdgeInsets.all(10),
//DENGAN DECORATION BERISI IMAGE YANG MEMENUHI CONTAINER
decoration: BoxDecoration(
image: DecorationImage(
image: AssetImage(
_images[index], //ADAPUN IMAGENYA DIAMBIL DARI VARIABLE _images BERDASARKAN INDEX LOOPING
),
fit: BoxFit.cover, //SET COVER AGAR MENUTUPI SELURUH SPACE CONTAINER
),
borderRadius: BorderRadius.circular(20), //BUAT MELENGKUNG SETIAP SUDUTNYA
),
);
}
Bagian terakhir adalah mendefinisikan variable berikut ini untuk kebutuhan gambar, pengaturan controller dari PageView.
PageController _pageController; //INISIASI VARIABLE _PAGECONTROLLER
int _currentSlide = 1; //INISIASI DEFAULT VALUE DARI CURRENT SLIDE
final _images = ['images/56.jpg', 'images/60.jpg', 'images/71.jpg'];
@override
void initState() {
_pageController = PageController(
initialPage: _currentSlide, //SLIDE YANG AKAN DISOROT BERDASARKAN VALUE DARI CURRENT SLIDE
keepPage: false,
viewportFraction: 0.5, //SEDANGKAN INI ADALAH UKURAN UNTUKS SETIAP CONTENT SLIDE
);
super.initState();
}
Download ketiga gambar yang ada di dalam variable images di repository daengweb dan simpan di dalam folder yang sama seperti sebelumnya, yakni images
. Kemudian modifikasi file pubspec.yaml
menjadi
assets:
- images/56.jpg
- images/60.jpg
- images/71.jpg
- images/bantimurung.jpg
- images/bira.jpg
- images/malino.jpg
- images/pantai-losari.jpg
- images/toraja.jpg
Adapun hasil akhir yang akan diperoleh terlihat seperti berikut
Baca Juga: Mengenal Widget Flutter #6: Grid View, ClipRRect & ClipPath, Hero Animation
Kesimpulan
Membuat carousel atau slide show di Flutter tidaklah sesulit yang dibayangkan, kita bisa memanfaatkan widget yang familiar seperti List View atau menggunakan widget yang berbeda seperti Page View. Sepanjang artikel ini kita banyak mengulang penggunaan widget yang telah lampau dan juga belajar menggunakan sebuah widget baru.
Semakin banyak case dalam belajar bahasa pemrograman akan semakin mudah dalam memahami bagaimana caranya bekerja
Adapun dokumentasi code dari artikel ini bisa dilihat di Github.
Comments