菠菜网

欧博亚洲电脑版下载:【Flutter 实战】简约而不简单的计算器

网址简介:未填写

更新时间:3个月前

访问次数:33

详细介绍

老孟导读:这是 【Flutter 实战】组件系列文章的最后一篇,其他组件地址:http://laomengit.com/guide/widgets/Text.html,接下来将会解说动画系列,关注老孟,精彩不停。

先看一下效果:

人人学习UI编程语言时喜欢用哪个 App 看成第一个练手的项目呢?,我喜欢使用 盘算器 ,可能是习惯了吧,学习 Android 和 React Native 都用此 App 看成练手的项目。

下面我会一步一步的教人人若何实现此项目。

整个项目的 UI 分为两大部门,一部门是顶部显示数字和盘算效果,另一部门是底部的输入按钮。

以是整体结构使用 Column,在差别分辨率的手机上,划定底部牢固巨细,剩余空间都由顶部组件填充,以是顶部组件使用 Expanded 扩充,代码如下:

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,
      )
    ],
  ),
)

SizedBox 组件用于两个组件之间的距离。

_CalculatorKeyboard 是底部的输入按钮组件,也是此项目的重点,除了 0 这个按钮外,其余都是圆形按钮,差别之处是 高亮颜色(按住时颜色)、靠山颜色、按钮文本、文本颜色差别,因此先实现一个按钮组件,代码如下:

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),
      ),
    ),
  ),
)

0 这个按钮的宽度是两个按钮的宽度 + 两个按钮的间隙,以是 0 按钮代码如下:

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: 158,
      height: 70,
      alignment: Alignment.center,
      child: Text(
        '0',
        style: TextStyle(color: Colors.white, fontSize: 24),
      ),
    ),
  ),
)

将按钮组件举行封装,其中高亮颜色(按住时颜色)、靠山颜色、按钮文本、文本颜色属性作为参数,封装如下:

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, borderRadius: BorderRadius.all(Radius.circular(200))),
      child: InkWell(
        onTap: () {
          onValueChange('$text');
        },
        borderRadius: BorderRadius.all(Radius.circular(200)),
        highlightColor: highlightColor ?? color,
        child: Container(
          width: width ?? 70,
          height: 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, fontSize: 24),
          ),
        ),
      ),
    );
  }
}

输入按钮

输入按钮的结构使用 Wrap 结构组件,若是没有 0 这个组件也可以使用 GridView组件,按钮的数据:

final List<Map> _keyboardList = [
  {
    'text': 'AC',
    'textColor': Colors.black,
    'color': Color(0xFFA5A5A5),
    'highlightColor': Color(0xFFD8D8D8)
  },
  {
    'text': '+/-',
    'textColor': Colors.black,
    'color': Color(0xFFA5A5A5),
    'highlightColor': Color(0xFFD8D8D8)
  },
  {
    'text': '%',
    'textColor': Colors.black,
    'color': Color(0xFFA5A5A5),
    'highlightColor': Color(0xFFD8D8D8)
  },
  {
    'text': '÷',
    'color': Color(0xFFE89E28),
    'highlightColor': Color(0xFFEDC68F)
  },
  {'text': '7', 'color': Color(0xFF363636)},
  {'text': '8', 'color': Color(0xFF363636)},
  {'text': '9', 'color': Color(0xFF363636)},
  {
    'text': 'x',
    'color': Color(0xFFE89E28),
    'highlightColor': Color(0xFFEDC68F)
  },
  {'text': '4', 'color': Color(0xFF363636)},
  {'text': '5', 'color': Color(0xFF363636)},
  {'text': '6', 'color': Color(0xFF363636)},
  {
    'text': '-',
    'color': Color(0xFFE89E28),
    'highlightColor': Color(0xFFEDC68F)
  },
  {'text': '1', 'color': Color(0xFF363636)},
  {'text': '2', 'color': Color(0xFF363636)},
  {'text': '3', 'color': Color(0xFF363636)},
  {
    'text': '+',
    'color': Color(0xFFE89E28),
    'highlightColor': Color(0xFFEDC68F)
  },
  {'text': '0', 'color': Color(0xFF363636), 'width': 158.0},
  {'text': '.', 'color': Color(0xFF363636)},
  {
    'text': '=',
    'color': Color(0xFFE89E28),
    'highlightColor': Color(0xFFEDC68F)
  },
];

整个输入按钮组件:

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,
        );
      }),
    );
  }
}

onValueChange 是点击按钮的回调,参数是当前按钮的文本,用于盘算,下面说下盘算逻辑:

这里有4个变量:

  • _text:显示当前输入的数字和盘算效果。
  • _beforeText:用于保留被加数,好比输入 5+1,保留 5 ,用于后面的盘算。
  • _isResult:示意当前值是否为盘算的效果,true:新输入数字直接显示,false:新输入数字和当前字符串相加,好比当前显示 5,若是是盘算的效果,点击 1 时,直接显示1,否则显示 51。
  • _operateText:保留加减乘除。

AC 按钮示意清空当前输入,显示 0,同时初始化其他变量:

case 'AC':
  _text = '0';
  _beforeText = '0';
  _isResult = false;
  break;

+/- 按钮示意对当前数字取反,好比 5->-5:

case '+/-':
  if (_text.startsWith('-')) {
    _text = _text.substring(1);
  } else {
    _text = '-$_text';
  }
  break;

% 按钮示意当前数除以100:

case '%':
  double d = _value2Double(_text);
  _isResult = true;
  _text = '${d / 100.0}';
  break;

+、-、x、÷ 按钮,保留当前 操作符号:

case '+':
case '-':
case 'x':
case '÷':
  _isResult = false;
  _operateText = value;

0-9 和 . 按钮凭据是否是盘算效果和是否有操作符号举行显示:

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);
    }
  }

回过头来,发现代码仅仅只有250多行,固然App也是有不足的地方:

  1. 不足之一:盘算效果逻辑,上面盘算效果的逻辑是不完善的,当增添一个操作符(好比 取余),盘算逻辑复杂度将会以指数级方式增添,那为什么还要用此方式?最主要的原因是盘算效果逻辑不是此项目的重点,作为一个Flutter的入门项目重点是熟悉组件的使用,盘算器的盘算逻辑有一个对照著名的方式:后缀表达式的盘算历程,然而此方式偏向于算法,对初学者异常不友好,因此,我采用了一种不完善但适合初学者的逻辑。
  2. 不足之二:此App没有思量横屏的情形,为什么?由于横屏很可能导致整体结构发生变化,横屏时按钮是变大照样拉伸,或者拉伸间隙?差别的方式使用的结构会发生变化,因此,现在只思量了竖屏的结构,现实项目中要思量横屏情形吗?实在这是一个用户体验的问题,首先问问自己,为什么要横屏?横屏可以显著的提升用户体验吗?若是不能,为什么要花费大气力适配横屏呢?

交流

老孟Flutter博客地址(330个控件用法):http://laomengit.com

迎接加入Flutter交流群(微信:laomengit)、关注民众号【老孟Flutter】:

,

欧博开户网址

欢迎进入欧博开户网址(Allbet Gaming):www.aLLbetgame.us,欧博网址开放会员注册、代理开户、电脑客户端下载、苹果安卓下载等业务。