Menggunakan Switch Widget

Switch Widget adalah widget yang berfungsi layaknya saklar on/off. Dapat kita gunakan untuk menampilkan atau tidak menampilkan suatu widget.

Untuk kasus aplikasi expense tracker, jika orientasi device adalah landscape, tampilan dari aplikasi akan menjadi berantakan. Pendekatan yang dilakukan adalah mengunci orientasi device selalu portrait (lihat modul sebelumnya untuk mengatur orientasi).

Atau kita buat alternative tampilan yang dapat ditampilkan atau disembunyikan menggunakan switch.

Code

import 'package:flutter/material.dart';
//import 'package:flutter/services.dart';

import './models/trans.dart';
import './widgets/expense_list.dart';
import './widgets/form_expense.dart';
import './widgets/chart.dart';

//void main() => runApp(MyApp());

void main() {
  //WidgetsFlutterBinding.ensureInitialized();
  //SystemChrome.setPreferredOrientations(
  //      [DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Expense Tracker',
      theme: ThemeData(
          primaryColor: Colors.red,
          accentColor: Colors.red[400],
          textTheme: TextTheme(
            bodyText2: TextStyle(
              color: Colors.red,
              fontFamily: 'Quicksand',
            ),
          ),
          fontFamily: 'OpenSans'),
      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()),
  ];

  bool _showChart = false;

  List<Trans> get _rcntTrx {
    return _trans.where((element) {
      return element.txdate.isAfter(DateTime.now().subtract(Duration(days: 7)));
    }).toList();
  }

  void _addNewExpense(String newTitle, double newAmount, DateTime newDate) {
    final newExpense = Trans(
        id: DateTime.now().toString(),
        title: newTitle,
        amount: newAmount,
        txdate: newDate);

    setState(() {
      _trans.add(newExpense);
    });
  }

  void _showFormExpense(BuildContext ctx) {
    showModalBottomSheet(
      context: ctx,
      builder: (_) {
        return FormExpense(_addNewExpense);
      },
    );
  }

  void _delExpense(String expId) {
    setState(() {
      _trans.removeWhere((element) {
        return element.id == expId;
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    final _mediaQuery = MediaQuery.of(context);
    final _isLandscape = _mediaQuery.orientation == Orientation.landscape;

    final _appBar = AppBar(
      title: Text('Expense Tracker'),
      actions: <Widget>[
        IconButton(
          icon: Icon(Icons.add),
          onPressed: () => _showFormExpense(context),
        )
      ],
    );

    final _screenSize = _mediaQuery.size.height -
        _appBar.preferredSize.height -
        _mediaQuery.padding.top;

    return Scaffold(
      appBar: _appBar,
      body: SingleChildScrollView(
        child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
              if (_isLandscape)
                Row(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                    Text('Show Chart'),
                    Switch(
                      value: _showChart,
                      onChanged: (val) {
                        setState(() {
                          _showChart = val;
                        });
                      },
                    ),
                  ],
                ),
              if (!_isLandscape)
                Container(height: _screenSize * 0.3, child: Chart(_rcntTrx)),
              if (!_isLandscape)
                Container(
                    height: _screenSize * 0.7,
                    child: ExpenseList(_trans, _delExpense)),
              if (_isLandscape)
                _showChart
                    ? Container(
                        height: _screenSize * 0.7, child: Chart(_rcntTrx))
                    : Container(
                        height: _screenSize * 0.7,
                        child: ExpenseList(_trans, _delExpense)),
            ]),
      ),
      floatingActionButtonLocation: FloatingActionButtonLocation.centerFloat,
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: () => _showFormExpense(context),
      ),
    );
  }
}

Penjelasan Code

Switch widget kita gunakan untuk mengatur variable boolean _showChart, yang nantinya variable ini akan digunakan untuk menampilkan atau menyembunyikan chart.

Karena perubahan value _showChart akan mengubah tampilan, maka perlu diwrap dalam fungsi setState().

Switch(
  value: _showChart,
  onChanged: (val) {
    setState(() {
      _showChart = val;
    });
  },
)

Untuk mengetahui status orientasi device, kita inisialisasi variable _isLandscape yang akan diisi dengan operasi logika membandingkan Orientasi saat ini dari MediaQuery object dengan enum Orientation.Landscape

Perintah dibawah _isLandscape akan true jika _mediaQuery.orientation adalah Landscape dan false jika Portrait.

Karena MediaQuery.of(context) digunakan berulang kali, kita definisikan variable _mediaQuery yang diisi dengan object MediaQuery.of(context). Ini bertujuan agar code lebih efisien.

final _mediaQuery = MediaQuery.of(context);
final _isLandscape = _mediaQuery.orientation == Orientation.landscape;

Berikutnya, jika variable _isLandscape adalah true (artinya device dalam keadaan landscape), maka Widget Switch akan ditampilkan.

child: Column(
    crossAxisAlignment: CrossAxisAlignment.stretch,
    children: <Widget>[
      if (_isLandscape)
        Row(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text('Show Chart'),
            Switch(
              value: _showChart,
              onChanged: (val) {
                setState(() {
                  _showChart = val;
                });
              },
            ),
          ],
        ),

Jika !_isLandscape (device dalam posisi Portrait), maka chart akan dan expense list akan ditampilkan

if (!_isLandscape)
  Container(height: _screenSize * 0.3, child: Chart(_rcntTrx)),
if (!_isLandscape)
  Container(
      height: _screenSize * 0.7,
      child: ExpenseList(_trans, _delExpense)),

Jika _isLandscape (device dalam posisi landscape), kita cek lagi, jika var _showChart true, maka tampilkan chart dengan ukuran height 70% dari screensize.

Jika _showCart false, maka tampilkan expense list dengan ukuran height 70% dari screensize.

if (_isLandscape)
  _showChart
      ? Container(
          height: _screenSize * 0.7, child: Chart(_rcntTrx))
      : Container(
          height: _screenSize * 0.7,
          child: ExpenseList(_trans, _delExpense)),

Dengan berakhirnya modul ini, maka berakhir juga tutorial Flutter Dasar. Kita akan bahas ditutorial Flutter lainnya untuk advanced issue seperti state management, http request, animation, database dan topik menarik lainnya.

Sharing is caring:

Leave a Comment