Mengenal Widget Flutter #2: Container, Stack & Positioned
Pendahuluan
Perkenalan lebih lanjut dengan widget Flutter yang banyak digunakan secara umum untuk membuat dan mengatur {layout|format|structure} pada aplikasi {mobile|cellular|cell} yang dibangun dengan Flutter. Container, Stack & Positioned akan menjadi materi pembahasan pada kesempatan kali ini untuk melengkapi materi sebelumnya yang membahas widget Row-Column.
Adapun alur dari materi ini adalah dengan membahas ketiga widget tersebut secara individu untuk memperlihatkan kegunaannya masing-masing, kemudian diakhir materi kita akan mengerjakan sebuah case sederhana dengan menyatukan ketiga widget tersebut dalam satu {frame|body}.
Baca Juga: Mengenal Widget Flutter #1: Scaffold & Row-Column
Beragam Fungsi Container
Secara bahasa,Portacamp Container jika diterjemahkan ke dalam bahasa indonesia maka hasilnya adalah wadah. Bagaikan sebuah wadah, container ini memiliki banyak fungsi untuk menampung objek lainnya atau sebagai dirinya sendiri. Beberapa step ke depan, kita akan berinteraksi dengan Container dengan menggunakan beragam attribute yang dimilikinya dan menggunakannya untuk menyelesaikan beberapa case.
Namun sebelum itu, kita mulai dengan Flutter {fresh|recent|contemporary} {install|set up}.
flutter create dw_container
Buka file lib/{main|primary|major}.dart dan modifikasi menjadi
import ‘{package|package deal|bundle}:flutter/{material|materials}.dart’;
void {main|primary|major}() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget {build|construct}(BuildContext context) {
return MaterialApp( home: Scaffold( appBar: AppBar( title: Text(‘Container’), ), body: Container( margin: EdgeInsets.all(10), color: Colors.pinkAccent, ), ),
);
}
}
Penjelasan: Fokusnya adalah membahas Container, jadi pada code di atas, kita membuat sebuah objek menggunakan Container dengan mengatur warnanya serta memberikan margin. EdgeInsets.all() artinya memberikan margin sebesar {value|worth} yang ada di dalamnya pada semua sisi (left, {top|prime|high}, {right|proper}, {bottom|backside}). Sifat dasar Container secara default akan memenuhi semua ruang yang diberikan.
Sedikit meng-{explore|discover} lebih jauh tentang apa saja yang bisa dilakukan dengan Container, dengan file yang sama lakukan modifikasi menjadi.
import ‘{package|package deal|bundle}:flutter/{material|materials}.dart’;
void {main|primary|major}() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget {build|construct}(BuildContext context) {
return MaterialApp( home: Scaffold( appBar: AppBar( title: Text(‘Container’), ), body: Container( margin: EdgeInsets.all(10), padding: EdgeInsets.all(15), color: Colors.pinkAccent, child: Container( decoration: BoxDecoration( color: Colors.lightGreen, gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [Colors.lightGreen, Colors.limeAccent], ), borderRadius: BorderRadius.circular(30), boxShadow: [ BoxShadow(blurRadius: 10), ], ), ), ), ),
);
}
}
Penjelasan: Container di dalam Container, jadi selain menjadi {parent|mother or father|father or mother}, juga bisa berperan sebagai {child|baby|youngster} widget. Case di atas kita membuat sebuah kotak besar yang berwarna pink dan di dalamnya terdapat kotak lainnya dengan warna gradient. Cara lain mewarnai Container adalah dengan menggunakan {parent|mother or father|father or mother} pada BoxDecoration. Adapun borderRadius berperan untuk mengatur lengkungan sudut dari kotak yang kita buat. Intinya adalah {decoration|ornament} ini memiliki banyak attribute untuk mengatur {style|type|fashion} dari container sesuai dengan keinginan penggunanya.
Meski tak sepaket tapi tak apalah kita jadikan berpasangan, jadi Stack itu memungkinkan widget yang ada di dalamnya ({red|purple|pink}: {children|youngsters|kids}) untuk di-set posisinya. Sehingga dengan bantuan Positioned maka kita dapat mengarahkan dimana posisi widget tersebut hendak ditempatkan.
Jadi schema yang diinginkan untuk mengenal cara kerja dari Stack dan Positioned kali adalah kita akan membuat sebuah kotak menggunakan container dan di sudut kanan bawah kotak tersebut terdapat kotak kecil yang berisikan {text|textual content} “Stack & Positioned”.
Buka file lib/{main|primary|major}.dart dan modifikasi menjadi
import ‘{package|package deal|bundle}:flutter/{material|materials}.dart’;
void {main|primary|major}() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget {build|construct}(BuildContext context) {
return MaterialApp( home: Scaffold( appBar: AppBar( title: Text(‘Container’), ), body: Stack( children: [ Container( color: Colors.orangeAccent, height: 250, ), Positioned( top: 195, left: 155, child: Container( height: 50, width: 250, color: Colors.black38, child: Center( child: Text( “Stack & Positioned”, style: TextStyle( color: Colors.white, fontWeight: FontWeight.bold, fontSize: 20, ), ), ), ), ) ], ), ),
);
}
}
Penjelasan: Stack itu hampir sama dengan Column dalam hal kesanggupan menampung widget, yakni bisa menampung lebih dari 1 widget sebagai {children|youngsters|kids}-nya. Hanya saja yang membedakan adalah widget yang ada di dalam Stack saling tumpang tindih sehingga dibutuhkan dekorasi lanjutan untuk menempatkan posisinya mau dibawa kemana. Sedangkan bagian yang penting dari Positioned adalah attribute {top|prime|high}, left, {bottom|backside}, {right|proper} yang berfungsi untuk mengatur jarak dari sudut sekitarnya.
Kesimpulan dari duet Stack & Positioned adalah kemampuan untuk mengatur tatak letak secara {custom|customized}, berbeda halnya dengan Column-Row yang menempatkan widget secara berurutan baik secara vertical dan horizontal.
Membuat UI Catatan Keuangan Pribadi
Setelah belajar fungsi dari masing-masing widget di atas, yakni: Container, Stack & Positioned, maka pada {part|half} kali ini kita akan menyelesaikan sebuah case sederhana sebagaimana screenshoot yang dilampirkan diawal materi, yaitu membuat UI atau tampilan aplikasi catatan keuangan pribadi.
Jika dilihat kembali gambar yang ada di pendahuluan, ada {3|three} buah object yang berbeda, pertama adalah sebuah container dengan warna pink disertai borderRadius pada posisi bawah dibuat sedikit melengkung. Kedua adalah container baru dengan warna putih dan diletakkan diatas container sebelumnya dengan memanfaatkan positioned. Bagian terakhir adalah Card yang dituliskan sebanyak {3|three} kali ({note|notice|observe}: Karena kita belum belajar listView dan materi ini masih sekedar UI) sebagai {history|historical past} pengeluaran dan pemasukan.
Sebaiknya {install|set up} Flutter yang baru, kemudian buka file lib/{main|primary|major}.dart dan modifikasi menjadi
import ‘{package|package deal|bundle}:flutter/{material|materials}.dart’;
void {main|primary|major}() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget {build|construct}(BuildContext context) {
return MaterialApp( debugShowCheckedModeBanner: false, home: Scaffold( body: Container( //MENGGUNAKAN COLUMN KARENA ADA DUA OBJEK YANG INGIN DIPISAHKAN //PERTAMA ADALAH HEADER BESERTA SUMMARYNYA DAN YANG KEDUA ADALAH HISTORY child: Column( children: [ //KITA GUNAKAN STACK UNTUK MENGATUR POSITION HEADER SERTA CONTAINER UNTUK SUMMARY Stack( children: [backgroundHeader(), summaryCash()], ), //BAGIAN INI AKAN MENAMPILKAN HISTORY PENGELUARAN cardDetail(‘Makan Siang’, ‘Beli Makan Di Warteg’, ‘10.000’, ‘out’), cardDetail(‘Bonus’, ‘Dapat Bonus Proyek’, ‘500.000’, ‘in’), cardDetail(‘Beli Baju’, ‘Baju Kemeja Kantor’, ‘250.000’, ‘out’), ], ), ), ),
);
}
}
Widget cardDetail(title, description, {price|worth|value}, {type|sort|kind}) {
//CARD UNTUK HISTORY PENGELUARAN
}
Widget summaryCash() {
//CONTAINER UNTUK SUMMARY PENGELUARAN DAN PEMASUKAN
}
Widget backgroundHeader() {
//CONTAINER UNTUK HEADER
}
Note: Bagian Header, Summary dan Card yang meng-{handle|deal with} {history|historical past} dipisahkan ke dalam masing-masing fungsi agar lebih mudah untuk mengelolanya sehingga tidak menumpuk.
Langkah pertama adalah kita kerjakan bagian header terlebih dahulu, modifikasi fungsinya menjadi
Widget backgroundHeader() {
//KITA BUAT CONTAINER DENGAN TINGGI SEBESAR 300, DAN LEBAR SEJAUH YANG BISA DIJANGKAU
//BOXDECORATIONNYA KITA SET WARNANYA PINKACCENT DAN PADA BAGIAN BAWAH KIRI-KANAN DIBUAT LENGKUNGAN
return Container(
height: 300,
width: double.infinity,
decoration: BoxDecoration( color: Colors.pinkAccent, borderRadius: BorderRadius.only( bottomLeft: Radius.circular(30), bottomRight: Radius.circular(30), ),
),
//ADAPUN CHILD DARI CONTAINER DIATAS KITA ATUR POSISINYA MENGGUNAKAN PADDING
child: Padding( //PADDINGNYA DI-SET HANYA UNTUK TOP DAN LEFT padding: const EdgeInsets.only(top: 60, left: 20), //KARENA KITA AKAN MENAMPILKAN LEBIH DARI 1 OBJEK YANG BERUSUSUN KEBAWAH //MAKA KITA GUNAKAN COLUMN child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ //BAGIAN INI NORMAL, HANYA MENAMPILKAN TEXT DENGAN STYLE MASING-MASING Text( “Anugrah Sandi”, style: TextStyle( fontSize: 25, color: Colors.white, fontWeight: FontWeight.bold), ), Text( ” “, style: TextStyle( fontSize: 15, color: Colors.white, ), ), ], ),
),
);
}
Jika di-run maka code di atas akan membentuk sebuah header berlatar pink dengan 2 buah teks di dalamnya. Selanjutnya adalah menempatkan {summary|abstract} di atas header tersebut, modifikasi fungsi summaryCash() menjadi
Widget summaryCash() {
//CONTAINER KEDUA INI BERWARNA PUTIH, KITA SET POSITIONEDNYA DENGAN MENENTUKAN VALUE DARI TOP DAN LEFT AGAR BERADA DITENGAH, DISESUAIKAN SAJA
return Positioned(
top: 180,
left: 20,
//CONTAINER KEDUA INI KITA BUAT LEBIH KECIL DENGAN MENENTUKAN WIDTH DAN HEIGHNYA TERBATAS
child: Container( width: 370, height: 140, //SAMA HALNYA DENGAN CONTAINER SEBELUMNYA, WARNANYA DI-SET DAN BORDERRADIUSNYA KALI INI BERBEDA KITA SET KE-4 SISINYA AGAR MELENGKUNG decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(30), ), //CHILD DARI CONTAINER INI DI-SET PADDINGNYA AGAR TERDAPAT JARAK DARI ATAS child: Padding( padding: const EdgeInsets.only(top: 30.0), //KARENA ADA DUA BAGIAN YANG BERBARIS DARI KIRI KE KANAN MAKA KITA GUNAKAN ROW() child: Row( //MAIN ALIGMENTNYA DI-SET SPACEAROUND AGAR KEDUA OBJEKNYA ADA JARAK YANG SESUAI mainAxisAlignment: MainAxisAlignment.spaceAround, crossAxisAlignment: CrossAxisAlignment.start, children: [ //MASING-MASING OBJECT MENGGUNAKAN COLUMN LAGI ADA DUA BUAH TEKS YANG INGIN DITAMPILKAN SECARA VERTICAL Column( children: [ Text(“Penghasilan”), Divider(), Text( “Rp 500.000”, style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold), ), ], ), Column( children: [ Text(“Pengeluaran”), Divider(), Text( “Rp 260.000”, style: TextStyle(fontSize: 25, fontWeight: FontWeight.bold), ), ], ), ], ), ),
),
);
}
Bagian terakhir adalah membuat Card {history|historical past}-nya, modifikasi fungsi cardDetail() menjadi
//KARENA INI SIFATNYA REUSABLE, MAKA KITA MEMINTA {3|three} DATA: TITLE, DESC, DAN PRICE
Widget cardDetail(title, description, {price|worth|value}, {type|sort|kind}) {
//BUAT CARD
return Card(
//DENGAN MARGIN YANG DISESUAIKAN
margin: EdgeInsets.only(top: 15, left: 15, right: 15),
//DENGAN KETEBALAN AGAR MEMBENTUK SHADOW SENILAI elevation: 8,
//CHILD DARI CARD MENGGUNAKAN LISTTILE AGAR LEBIH MUDAH MENGATUR AREANYA
//KARENA SECARA DEFAULT LISTTILE TELAH TERBAGI MENJADI 3 BAGIAN
//POSISI KIRI (LEADING), TENGAH (TITLE), BAWAH TENGAH (SUBTITLE) DAN KANAN(TRAILING)
//SEHINGGA KITA HANYA TINGGAL MEMASUKKAN TEKS YANG SESUAI
child: ListTile( leading: Icon( type == ‘out’ ? Icons.subdirectory_arrow_left:Icons.subdirectory_arrow_right, color: type == ‘out’ ? Colors.redAccent:Colors.lightGreen, ), title: Text( title, style: TextStyle(fontWeight: FontWeight.bold), ), subtitle: Text(description), trailing: Text( “Rp “+price, style: TextStyle(color: type == ‘out’ ? Colors.redAccent:Colors.lightGreen), ),
),
);
}
Jika di-save dan di-run maka hasil yang akan diperoleh akan sesuai dengan gambar yang telah dilampirkan sebelumnya dan hanya bermodalkan Container, Stack & Positioned maka kita sudah bisa membuat sebuah UI yang sederhana tapi menarik untuk digunakan.
Baca Juga: Aplikasi E-Commerce Laravel 6 #10: Multiple Authentication
Kesimpulan
Memahami Flutter adalah tentang memahami bagaimana cara menggunakan widget yang dimilikinya, karena {layout|format|structure} yang dihasilkannya adalah kombinasi dari satu widget dengan widget lainnya. Tapi kan attribute-nya banyak? Ingat dalam dunia pemrograman tidak semua hal yang disediakan oleh bahasa pemrograman atau framework itu sering digunakan, maka pahami cara kerja attribute yang umum digunakan.