I am developing a loan calculator in Flutter, and everything works fine except for a small UI issue. There is a broken “X-box” icon next to the dropdown button for selecting the repayment method. I can’t seem to fix or remove this icon.
Here is the code I am using for the dropdown:
[this is the xbox](https://i.sstatic.net/jyhJo3yF.png)
(https://i.sstatic.net/cWPDnIWg.png)
DropdownButtonFormField<String>(
value: _selectedRepaymentOption,
decoration: const InputDecoration(?
labelText: 'Repayment Method',
border: OutlineInputBorder(),
),
isExpanded: true,
onChanged: (String? newValue) {
setState(() {
_selectedRepaymentOption = newValue!;
});
},
items: _repaymentOptions.map((String option) {
return DropdownMenuItem<String>(
value: option,
child: Text(option),
);
}).toList(),
),
Repayment options:
Equal Payment
Deferred Equal Payment
Bullet Payment
Issue: The dropdown works, but next to it, there’s an icon showing a small box with an “X” (like a broken image or placeholder icon). This happens in both Chrome and on Android.
What I have tried:
Removing the const keyword in case it was causing constructor issues.
Checking for overflow or layout issues.
Resizing the widget to ensure it fits the UI.
Despite these efforts, the issue persists. How can I remove this broken icon, or what might be causing it?
Here is the full code of the loan calculator:
import 'dart:math';
import 'package:flutter/material.dart';
class LoanCalculator extends StatefulWidget {
const LoanCalculator({Key? key}) : super(key: key);
@override
LoanCalculatorState createState() => LoanCalculatorState();
}
class LoanCalculatorState extends State<LoanCalculator> {
final TextEditingController principalController = TextEditingController();
final TextEditingController interestRateController = TextEditingController();
final TextEditingController yearsController = TextEditingController();
final TextEditingController gracePeriodController = TextEditingController(); // Grace period input field
String _selectedRepaymentOption = 'Equal Payment'; // Default repayment method
String _result = '';
final List<String> _repaymentOptions = [
'Equal Payment',
'Deferred Equal Payment',
'Bullet Payment'
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Loan Calculator'),
),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
TextField(
controller: principalController,
decoration: const InputDecoration(
labelText: 'Loan Amount (KRW)',
),
keyboardType: TextInputType.number,
),
const SizedBox(height: 20),
TextField(
controller: interestRateController,
decoration: const InputDecoration(
labelText: 'Annual Interest Rate (%)',
),
keyboardType: TextInputType.number,
),
const SizedBox(height: 20),
TextField(
controller: yearsController,
decoration: const InputDecoration(
labelText: 'Loan Term (years)',
),
keyboardType: TextInputType.number,
),
const SizedBox(height: 20),
DropdownButtonFormField<String>(
value: _selectedRepaymentOption,
decoration: const InputDecoration(
labelText: 'Repayment Method',
border: OutlineInputBorder(),
),
isExpanded: true,
onChanged: (String? newValue) {
setState(() {
_selectedRepaymentOption = newValue!;
});
},
items: _repaymentOptions.map((String option) {
return DropdownMenuItem<String>(
value: option,
child: Text(option),
);
}).toList(),
),
const SizedBox(height: 20),
// Show grace period input field when "Deferred Equal Payment" is selected
if (_selectedRepaymentOption == 'Deferred Equal Payment') ...[
TextField(
controller: gracePeriodController,
decoration: const InputDecoration(
labelText: 'Grace Period (years)',
),
keyboardType: TextInputType.number,
),
const SizedBox(height: 20),
],
ElevatedButton(
onPressed: _calculateLoan,
child: const Text('Calculate'),
),
const SizedBox(height: 20),
Text(
_result,
style: const TextStyle(fontSize: 18),
),
],
),
),
);
}
void _calculateLoan() {
double principal = double.tryParse(principalController.text) ?? 0;
double annualInterestRate = double.tryParse(interestRateController.text) ?? 0 / 100;
int years = int.tryParse(yearsController.text) ?? 0;
if (principal == 0 || annualInterestRate == 0 || years == 0) {
setState(() {
_result = 'Please enter valid values in all fields.';
});
return;
}
double result = 0;
if (_selectedRepaymentOption == 'Equal Payment') {
result = _equalPayment(principal, annualInterestRate, years);
} else if (_selectedRepaymentOption == 'Deferred Equal Payment') {
int gracePeriod = int.tryParse(gracePeriodController.text) ?? 0;
result = _deferredEqualPayment(principal, annualInterestRate, years, gracePeriod);
} else if (_selectedRepaymentOption == 'Bullet Payment') {
result = _bulletPayment(principal, annualInterestRate, years);
}
setState(() {
_result = 'Monthly Payment: ₩${result.toStringAsFixed(2)}';
});
}
// Equal Payment calculation
double _equalPayment(double principal, double annualInterestRate, int years) {
double monthlyInterestRate = annualInterestRate / 12;
int totalPayments = years * 12;
return (principal * monthlyInterestRate) /
(1 - pow(1 + monthlyInterestRate, -totalPayments));
}
// Deferred Equal Payment calculation
double _deferredEqualPayment(
double principal, double annualInterestRate, int years, int gracePeriod) {
double monthlyInterestRate = annualInterestRate / 12;
int totalPayments = (years - gracePeriod) * 12;
return (principal * monthlyInterestRate) /
(1 - pow(1 + monthlyInterestRate, -totalPayments));
}
// Bullet Payment calculation
double _bulletPayment(
double principal, double annualInterestRate, int years) {
return principal * pow(1 + annualInterestRate, years);
}
}
To resolve the issue, you have two options:
- Enable Material Icons in your project
By default, DropdownButtonFormField
uses a material icon in that position. To ensure the icon displays correctly, make sure you have uses-material-design: true
in your project’s pubspec.yaml file under the flutter:
section:
flutter:
uses-material-design: true
This ensures that Material Icons are included as part of your project.
- Set a Custom Icon
If you prefer to customize the icon or don’t want to add Material Icons to your project, you can set your own icon in the DropdownButtonFormField
‘s icon
property:
DropdownButtonFormField<String>(
...
icon: MyCustomIcon(),
...
)