Container(
padding: EdgeInsets.symmetric(horizontal: 18),child: Column(
children: <Widget>[
Expanded(
child: Container(
alignment: Alignment.bottomRight,padding: EdgeInsets.only(right: 10),child: Text(
'$_text',maxLines: 1,style: TextStyle(
color: Colors.white,fontSize: 48,fontWeight: FontWeight.w400),),SizedBox(
height: 20,_CalculatorKeyboard(
onValueChange: _onValueChange,SizedBox(
height: 80,)
],)
Ink(
decoration: BoxDecoration(
color: Color(0xFF363636),borderRadius: BorderRadius.all(Radius.circular(200))),child: InkWell(
borderRadius: BorderRadius.all(Radius.circular(200)),highlightColor: Color(0xFF363636),child: Container(
width: 70,height: 70,alignment: Alignment.center,child: Text(
'1',style: TextStyle(color: Colors.white,fontSize: 24),)
Ink(
decoration: BoxDecoration(
color: Color(0xFF363636),child: Container(
width: 158,child: Text(
'0',)
class _CalculatorItem extends StatelessWidget {
final String text;
final Color textColor;
final Color color;
final Color highlightColor;
final double width;
final ValueChanged<String> onValueChange;
_CalculatorItem(
{this.text,this.textColor,this.color,this.highlightColor,this.width,this.onValueChange});
@override
Widget build(BuildContext context) {
return Ink(
decoration: BoxDecoration(
color: color,child: InkWell(
onTap: () {
onValueChange('$text');
},borderRadius: BorderRadius.all(Radius.circular(200)),highlightColor: highlightColor ?? color,child: Container(
width: width ?? 70,padding: EdgeInsets.only(left: width == null ? 0 : 25),alignment: width == null ? Alignment.center : Alignment.centerLeft,child: Text(
'$text',style: TextStyle(color: textColor ?? Colors.white,);
}
}
输入按钮
final List<Map> _keyboardList = [
{
'text': 'AC','textColor': Colors.black,'color': Color(0xFFA5A5A5),'highlightColor': Color(0xFFD8D8D8)
},{
'text': '+/-',{
'text': '%',{
'text': '÷','color': Color(0xFFE89E28),'highlightColor': Color(0xFFEDC68F)
},{'text': '7','color': Color(0xFF363636)},{'text': '8',{'text': '9',{
'text': 'x',{'text': '4',{'text': '5',{'text': '6',{
'text': '-',{'text': '1',{'text': '2',{'text': '3',{
'text': '+',{'text': '0','color': Color(0xFF363636),'width': 158.0},{'text': '.',{
'text': '=',];
class _CalculatorKeyboard extends StatelessWidget {
final ValueChanged<String> onValueChange;
const _CalculatorKeyboard({Key key,this.onValueChange}) : super(key: key);
@override
Widget build(BuildContext context) {
return Wrap(
runSpacing: 18,spacing: 18,children: List.generate(_keyboardList.length,(index) {
return _CalculatorItem(
text: _keyboardList[index]['text'],textColor: _keyboardList[index]['textColor'],color: _keyboardList[index]['color'],highlightColor: _keyboardList[index]['highlightColor'],width: _keyboardList[index]['width'],onValueChange: onValueChange,);
}),);
}
}
-
_text:显示当前输入的数字和计算结果。
-
_beforeText:用于保存被加数,比如输入 5+1,保存 5 ,用于后面的计算。
-
_isResult:表示当前值是否为计算的结果,true:新输入数字直接显示,false:新输入数字和当前字符串相加,比如当前显示 5,如果是计算的结果,点击 1 时,直接显示1,否则显示 51。
-
_operateText:保存加减乘除。
case 'AC':
_text = '0';
_beforeText = '0';
_isResult = false;
break;
case '+/-':
if (_text.startsWith('-')) {
_text = _text.substring(1);
} else {
_text = '-$_text';
}
break;
case '%':
double d = _value2Double(_text);
_isResult = true;
_text = '${d / 100.0}';
break;
case '+':
case '-':
case 'x':
case '÷':
_isResult = false;
_operateText = value;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case '.':
if (_isResult) {
_text = value;
}
if (_operateText.isNotEmpty && _beforeText.isEmpty) {
_beforeText = _text;
_text = '';
}
_text += value;
if (_text.startsWith('0')) {
_text = _text.substring(1);
}
break;
case '=':
double d = _value2Double(_beforeText);
double d1 = _value2Double(_text);
switch (_operateText) {
case '+':
_text = '${d + d1}';
break;
case '-':
_text = '${d - d1}';
break;
case 'x':
_text = '${d * d1}';
break;
case '÷':
_text = '${d / d1}';
break;
}
_beforeText = '';
_isResult = true;
_operateText = '';
break;
double _value2Double(String value) {
if (_text.startsWith('-')) {
String s = value.substring(1);
return double.parse(s) * -1;
} else {
return double.parse(value);
}
}
- 不足之一:计算结果逻辑,上面计算结果的逻辑是不完美的,当增加一个操作符(比如 取余),计算逻辑复杂度将会以指数级方式增加,那为什么还要用此方式?最重要的原因是计算结果逻辑不是此项目的重点,作为一个Flutter的入门项目重点是熟悉组件的使用,计算器的计算逻辑有一个比较著名的方式:后缀表达式的计算过程,然而此方式偏向于算法,对初学者非常不友好,因此,我采用了一种不完美但适合初学者的逻辑。
- 不足之二:此App没有考虑横屏的情况,为什么?因为横屏很可能导致整体布局发生变化,横屏时按钮是变大还是拉伸,或者拉伸间隙?不同的方式使用的布局会发生变化,因此,目前只考虑了竖屏的布局,实际项目中要考虑横屏情况吗?其实这是一个用户体验的问题,首先问问自己,为什么要横屏?横屏可以显著的提升用户体验吗?如果不能,为什么要花费大力气适配横屏呢?