Pada modul ini kita akan pisahkan widget pada aplikasi menjadi beberapa widget. Selain itu perlu juga melakukan organizing file. Organizing file untuk proyek besar akan sangat membantu kita.
File Organizing
Disarankan untuk memisahkan file custom widget yang kita buat kedalam folder terpisah. Dan untuk file class non widget kedalam folder yang terpisah juga
Pada proyek file trans.dart, yaitu file class untuk model data transaksi expense dimasukan kedalam folder models.
Sementara untuk custom widget (widget untuk form input, expense list), dimasukan kedalam folder widgets.
Note: Untuk penamaan folder bebas, tidak ada aturan khusus.
Code Aplikasi
//file main.dart
import 'package:flutter/material.dart';
import './models/trans.dart';
import './widgets/expense_list.dart';
import './widgets/form_expense.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final List<Trans> _trans = [
Trans(
id: 'a001',
title: 'Notebook Aspire A5',
amount: 8200000,
txdate: DateTime.now()),
Trans(
id: 'a002',
title: 'Samsung Galaxy A5',
amount: 3200000,
txdate: DateTime.now()),
];
void _addNewExpense(String newTitle, double newAmount) {
final newExpense = Trans(
id: DateTime.now().toString(),
title: newTitle,
amount: newAmount,
txdate: DateTime.now());
setState(() {
_trans.add(newExpense);
});
}
void _showFormExpense(BuildContext ctx) {
showModalBottomSheet(
context: ctx,
builder: (_) {
return FormExpense(_addNewExpense);
},
);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Expense Tracker'),
actions: <Widget>[
IconButton(
icon: Icon(Icons.add),
onPressed: () => _showFormExpense(context),
)
],
),
body: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Card(
color: Colors.blue,
child: Text('Chart'),
),
ExpenseList(_trans),
]),
),
floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () => _showFormExpense(context),
),
);
}
}
File form_expense.dart akan berisi widget yang menampilkan form untuk melakukan user input.
// file form_expense.dart
import 'package:flutter/material.dart';
class FormExpense extends StatefulWidget {
final Function addExpenseH;
FormExpense(this.addExpenseH);
@override
_FormExpenseState createState() => _FormExpenseState();
}
class _FormExpenseState extends State<FormExpense> {
final titleCtrl = TextEditingController();
final amountCtrl = TextEditingController();
void submitForm() {
final inpTitle = titleCtrl.text;
final inpAmount = double.parse(amountCtrl.text);
if (inpAmount <= 0 || inpTitle.isEmpty) {
return;
}
widget.addExpenseH(titleCtrl.text, double.parse(amountCtrl.text));
Navigator.of(context).pop();
}
@override
Widget build(BuildContext context) {
return Card(
child: Container(
padding: EdgeInsets.all(7),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
TextField(
decoration: InputDecoration(labelText: 'Title'),
controller: titleCtrl,
),
TextField(
decoration: InputDecoration(labelText: 'Amount'),
controller: amountCtrl,
keyboardType: TextInputType.number,
),
FlatButton(
onPressed: submitForm,
child: Text('Add Expense'),
textColor: Colors.red,
),
],
),
),
);
}
}
File expense_list.dart berisi widget yang menampilkan expense list.
// file expense_list.dart
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import '../models/trans.dart';
class ExpenseList extends StatelessWidget {
final List<Trans> _trans;
ExpenseList(this._trans);
@override
Widget build(BuildContext context) {
return Container(
height: 300,
child: ListView.builder(
itemCount: _trans.length,
itemBuilder: (ctx, idx) {
return Card(
child: Row(
children: <Widget>[
Container(
padding: EdgeInsets.all(6),
margin: EdgeInsets.symmetric(
vertical: 10,
horizontal: 15,
),
decoration: BoxDecoration(
border: Border.all(color: Colors.red, width: 2)),
child: Text(
// 'Rp. ${trx.amount}',
NumberFormat.currency(symbol: 'Rp. ', decimalDigits: 0)
.format(_trans[idx].amount),
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
color: Colors.red),
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
_trans[idx].title,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 12,
),
),
Text(
DateFormat.yMMMd().format(_trans[idx].txdate),
style: TextStyle(fontSize: 10, color: Colors.grey),
),
],
)
],
),
);
},
),
);
}
}
Pembahasan Code
Pembahasan code akan kita lakukan pada modul berikutnya.