BMI atau Body Mass Index adalah suatu cara untuk mengetahui apakah berat badan berada dalam kategori ideal, kurang ataupun berlebih dengan menggunakan perbandingan berat badan dan tinggi badan. Cara hitungnya adalah dengan cara menghitung berat badan input dalam kilogram dan dibagi dengan tinggi badan input dalam meter dan dikuadratkan sehingga secara logika perhitungannya adalah BMI = Kg/M².

BMI merupakan suatu alat yang digunakan untuk skrining awal dengan cepat dan praktis dalam mendeteksi adanya risiko masalah pada kesehatan. Namun kekurangan dari BMI adalah BMI tidak memperhitungkan dan tidak membedakan indeks pada massa otot dan juga lemak sehingga hasilnya mungkin tidak sangat akurat untuk seseorang dengan kondisi tertentu seperti atlet atau binaragawan.

Langkah Praktikum

Pada praktikum kali ini adalah terkait dengan perbaikan kode program kalkulator BMI yang telah diberikan agar dapat digunakan secara normal tanpa ada tampilan yang mengganggu, jadi langsung saja kita mulai.

None

Pada kode awal yang diberikan sebenarnya logika kode sudah berjalan dengan baik, namun tetap diperlukan sedikit perbaikan terkait UI agar tampilan dapat terlihat lebih baik dan terstruktur, perbaikan yang diperlukan adalah terkait dengan menambahkan SingleChildScrollView yang digunakan untuk melakukan scroll/menggulir layar ketika beberapa widget yang ada telah memenuhi layar sehingga diperlukan cara untuk menggulir layar agar semua fungsi dapat berjalan dengan lancar tanpa saling tumpang tindih.

Selain itu agar tampilan terasa lebih enak dipandang dan digunakan, perlu dilakukan beberapa penyesuaian terkait dari ConstrainedBox yang awalnya membentang dari ujung kiri hingga kanan menjadi cukup berada ditengah menggunakan Center, selain itu agar menambah UI dan kecepatan user dalam memahami sesuatu, diperlukan juga penambahan icon terutama pada bagian berat badan, tinggi badan dan pemilihan kategori.

Selain itu pemilihan jenis kelamin yang secara vertikal juga dirasa kurang enak dipandang secara UI dan kurang nyaman digunakan secara UX sehingga perlu adanya sedikit perubahan yaitu, dengan cara mengganti constrained yang awalnya column menjadi row. Dengan semua penggantian ini maka dapat dihasilkan hasil yang seperti dibawah ini:

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

import 'result_page.dart';

class InputPage extends StatefulWidget {
  const InputPage({super.key});

  @override
  State<InputPage> createState() => _InputPageState();
}

class _InputPageState extends State<InputPage> {
  final _formKey = GlobalKey<FormState>();
  final _nameController = TextEditingController();
  final _weightController = TextEditingController();
  final _heightController = TextEditingController();

  String? _selectedCategory;

  final List<String> _categories = [
    'Anak-anak',
    'Remaja',
    'Dewasa',
  ];

  String _selectedGender = 'Laki-laki';
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Kalkulator BMI"),
      ),
      body: Center(
        child: ConstrainedBox(constraints: BoxConstraints(maxWidth: 500),
        child: SingleChildScrollView(
        key: _formKey,
        child: Padding(
          padding: EdgeInsets.all(16),
          child: Column(
            children: [
              // TextFormField untuk nama
              TextFormField(
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Mohon isi data ini'; ng
                  }
                  return null;
                },
                controller: _nameController,
                decoration: InputDecoration(
                  labelText: 'Nama Lengkap',
                  hintText: 'Masukkan nama...',
                  prefixIcon: Icon(Icons.person),
                  border: OutlineInputBorder(
                    borderRadius:BorderRadius.circular(15)
                  ),
                ),
                textCapitalization: TextCapitalization.words,
              ),
              SizedBox(height: 30),
              TextFormField(
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Mohon isi data ini';
                  }
                  return null; 
                },
                controller: _weightController,
                decoration: InputDecoration(
                  labelText: 'Berat Badan',
                  hintText: 'Contoh: 65',
                  prefixIcon: Icon(Icons.monitor_weight),
                  suffixText: 'kg',
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(15)
                  ),
                ),
                keyboardType: TextInputType.number,
                inputFormatters: [
                  FilteringTextInputFormatter.digitsOnly,
                ],
              ),
              SizedBox(height: 30),
              TextFormField(
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Mohon isi data ini';
                  }
                  return null;
                },
                controller: _heightController,
                decoration: InputDecoration(
                  labelText: 'Tinggi Badan',
                  hintText: 'Contoh: 170',
                  prefixIcon: Icon(Icons.height),
                  suffixText: 'cm',
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(15)
                  ),
                ),
                keyboardType: TextInputType.number,
                inputFormatters: [
                  FilteringTextInputFormatter.digitsOnly,
                ],
              ),
              SizedBox(height: 30),
              DropdownButtonFormField<String>(
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'Mohon isi data ini';
                  }
                  return null;
                },
                value: _selectedCategory,
                decoration: InputDecoration(
                  labelText: 'Kategori Usia',
                  border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(15)
                  ),
                  prefixIcon: Icon(Icons.elderly)
                ),
                hint: Text('Pilih kategori...'),
                items: _categories.map((category) {
                  return DropdownMenuItem(
                    value: category,
                    child: Text(category),
                  );
                }).toList(),
                onChanged: (value) {
                  setState(() {
                    _selectedCategory = value;
                  });
                },
              ),
              SizedBox(height: 30),
              Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    'Jenis Kelamin',
                    style: TextStyle(fontWeight: FontWeight.w500),
                  ),
                  SizedBox(height: 8),
                  Row(
                    children: [
                      Expanded(
                        child:  RadioListTile<String>(
                    title: Text('Laki-laki'),
                    value: 'Laki-laki',
                    groupValue: _selectedGender,
                    onChanged: (value) {
                      setState(() {
                        _selectedGender = value!;
                      });
                    },
                  ),),
                  Expanded(
                    child: RadioListTile<String>(
                      contentPadding: EdgeInsets.zero,
                    title: Text('Perempuan'),
                    value: 'Perempuan',
                    groupValue: _selectedGender,
                    onChanged: (value) {
                      setState(() {
                        _selectedGender = value!;
                      });
                    },
                  ), )  
                    ],
                  )
                ],
              ),
              SizedBox(
              height: 50, 
              child: ElevatedButton(
                style: ElevatedButton.styleFrom(
                  backgroundColor: Colors.blueAccent, 
                  foregroundColor: Colors.white, 
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(12), 
                  ),
                ),
                onPressed: () {
                  if (_formKey.currentState!.validate()) {
                    final nama = _nameController.text;
                    final berat = double.parse(_weightController.text);
                    final tinggi = double.parse(_heightController.text) / 100;
                    final bmi = berat / (tinggi * tinggi);
                    
                    Navigator.push(
                      context,
                      MaterialPageRoute(
                        builder: (context) => ResultPage(
                          nama: nama,
                          bmi: bmi,
                          gender: _selectedGender,
                          kategori: _selectedCategory!,
                        ),
                      ),
                    );
                  }
                },
                child: Text(
                  "Hitung",
                  style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
                ),
              ),
            ),
            ],
          ),
        ),
      )),
    ));
  }
}

Oke, langkah awal yaitu menemukan kekurangan dari kode awal telah berhasil, selanjutnya kita akan membuat kalkulator BMI menjadi lebih layak dan lebih menarik dengan melakukan banyak perubahan yaitu:

  1. Mengubah struktur kode, yang awalnya kode hanya ada main.dart, theme.dart, input_page.dart, dan result_page.dart menjadi terdapat penambahan yaitu splash_page.dart yang digunakan sebagai transisi awal dan juga home_page.dart untuk membuat dashboard utama untuk navigasi sistem.
  2. Mengganti theme secara keseluruhan dan juga menggunakan widget BackdropFilter untuk memberikan kesan blur.
  3. Melakukan penggunaan function GestureDetector yang digunakan untuk menambah atau mengurangi berat badan atau umur dan juga menggunakan Timer.periodic untuk kemudahan user dalam mengisi inputan yang jauh dari nilai default dengan cukup menahan tombol + atau — agar dapat menghasilkan nilai yang sesuai dengan keinginan secara cepat dan modern.
  4. Melakukan penambahan fitur profile menggunakan overlay dengan function showModalBottomSheet agar modal profile dapat dioverlay dari bawah ke atas dan menggunakan isScrollControlled: true agar modal yang keluar hanya mencapai setengah dari total tinggi layar. Selain itu layar juga menggunakan StatefulWidget agar dapat berubah ubah secara cepat dan fleksibel. Dan juga terdapat showDialog untuk memunculkan modal input nama pada overlay profile dan juga memanggil function setState() untuk mengganti teks penyapaan pada home page agar sesuai dengan inputan user pada modal input nama.
  5. Menambahkan conditional statement terhadap status hasil user menggunakan function getEducationData yang digunakan menggunakan ListView.builder.

Maka untuk hasilnya adalah sebagai berikut:

None
None
None
None
None
Perubahan setState pada nama
None
Edukasi terkait langkah yang diperlukan agar dapat menjaga berat badan ideal

Kesimpulan

Perbaikan kode awal dapat memberikan gambaran jelas terkait seberapa penting SingleChildScrollView dalam kode program, selain itu modifikasi secara menyeluruh dapat mengubah bentuk program awal menjadi lebih terstruktur dan menjadi memiliki nilai tambah dalam penggunaannya baik pada tampilannya (UI) ataupun juga pengalaman pengguna (UX) dalam memakai produk ini secara langsung.