Flutter for App——一个简单的BMI计算APP

news2024/11/28 0:44:23

一个简单的BMI计算APP

  • 效果截图
    • 初始化
    • 布局
      • 顶部区域
        • 标题
        • 计算结果
        • 组合顶部区域
        • 背景
      • 中间区域
        • 输入框
        • 输入行
        • 计算按钮
        • 分界线
        • 组合中间区域
      • 底部区域
      • 页面组合
    • BMI计算
    • Toast弹窗
      • 效果
      • 导入依赖
      • 封装

效果截图

初始化

初始化表单控制器和焦点节点

void initView(){
    formKey = GlobalKey<FormState>();
    heightController = TextEditingController();
    weightController = TextEditingController();
    heightNode = FocusNode();
    weightNode = FocusNode();
  }

为体重和升高焦点节点进行事件监听,并改变状态标志位

void addListener(){
    heightNode.addListener(() {
      if(heightController.text.isNotEmpty){
        heightClear = true;
      }else{
        heightClear = false;
      }
    });

    weightNode.addListener(() {
      if(weightController.text.isNotEmpty){
        weightClear = true;
      }else{
        weightClear = false;
      }
    });
  }

布局

顶部区域

标题

没有使用系统标题栏,通过将Text文本放到中间,作为标题使用

 ///标题
    Widget title = Center(
        child: Text(titleText,style: getTextStyle(18.0, Colors.white, FontWeight.bold),)
    );

计算结果

身体状况和标准体重通过Expanded各占一半宽度,并各执一边

///结果匹配值
    Widget physical = Row(
      children: [
        Expanded(child: Text(body,style: getTextStyle(12.0, Colors.white, FontWeight.normal),textAlign: TextAlign.left,)),
        Expanded(child: Text(standardWeight,style: getTextStyle(12.0, Colors.white, FontWeight.normal),textAlign: TextAlign.right))
      ],
    );

组合顶部区域

然后通过Column进行垂直排列,其中使用const SizedBox(height: 30.0,)做完高度间隔分隔符

///BMI计算结果
    Widget bmiResult = Column(
      children: [
        const SizedBox(height: 40.0,),
        title,
        const SizedBox(height: 30.0,),
        Align( alignment:Alignment.topLeft ,child: Text('BMI',style: getTextStyle(14.0, Colors.white, FontWeight.bold))),
        const SizedBox(height: 10.0,),
        Align( alignment:Alignment.topLeft ,child: Text(bmi,style: getTextStyle(24.0, Colors.white, FontWeight.bold))),
        const SizedBox(height: 20.0,),
        physical,
        const SizedBox(height: 20.0,),
        Align( alignment:Alignment.topLeft ,child: Text(diseaseTip,style: getTextStyle(12.0, Colors.white, FontWeight.normal))),
      ],
    );

背景

最后将上列用Container但布局进行包裹,并设置背景颜色

Widget topArea = Container(
      color: Colors.green,
      padding: const EdgeInsets.all(20.0),
      child: bmiResult,
    );

中间区域

中间区域包括两个输入框和计算按钮

输入框

身高和体重输入行一致,此处以身高为例;身高TextFormField包括啦上述初始化的控制权和焦点节点,并添加了一个末尾Icon,当输入内容不为空时,显示清空按钮,并对点击事件做清空处理,在onSaved中对输入的内容进行保存

   /**
     * 身高输入框*/
    Widget heightArea = Container(
      padding: const EdgeInsets.all(2.0),
      decoration: const BoxDecoration(
        shape: BoxShape.rectangle,
        borderRadius: BorderRadius.all(Radius.circular(5.0)),
        color: Colors.white30
      ),
      child: TextFormField(
        maxLines: 1,
        keyboardType: TextInputType.number,
        controller: heightController,
        focusNode: heightNode,
        decoration: InputDecoration(
            hintText: '请输入身高',
            hintStyle: getTextStyle(14.0, Colors.grey, FontWeight.normal),
            border: InputBorder.none,
            suffixIcon: heightClear ?
            IconButton(
                onPressed: (){heightController.clear();},
                icon: const Icon(Icons.clear)) : null
        ),
        onSaved: (value){
          inputHeight = value.toString();
        },
      ),
    );

输入行

然后用Row布局水平排列,同样使用 const SizedBox(width: 20.0,)做水平间隔分隔符

/**
     * 身高行*/
    Widget height = Row(
      children: [
        Text('身高',style: getTextStyle(16.0, Colors.grey, FontWeight.bold),),
        const SizedBox(width: 20.0,),
        Expanded(child: heightArea),
        const SizedBox(width: 20.0,),
        Text('CM',style: getTextStyle(16.0, Colors.grey, FontWeight.bold),),
      ],
    );

计算按钮

然后使用ElevatedButton,并对点击事件做计算处理

  ///计算按钮
    Widget calculateButton = SizedBox(
      width: 300.0,
      height: 50.0,
      child: ElevatedButton(
        onPressed: (){
          if(formKey.currentState!.validate()){
            formKey.currentState!.save();
            //do calculate tings
            BMICalculate(inputHeight,inputWeight);
          }
        },
        style: ButtonStyle(
          backgroundColor: MaterialStateProperty.all(Colors.green),
        ),
        child: Text('开始计算',style: getTextStyle(16.0, Colors.white, FontWeight.bold),),
      ),
    );

分界线

 /// 分界线
    Widget splitLine = const SizedBox(
      height: 1.0,
      width: double.infinity,
      child: DecoratedBox(
        decoration: BoxDecoration(color: Colors.grey),
      ),
    );

组合中间区域

并对表单进行监听,并通过Column进行子组件布局

Widget centerArea = Form(
      key: formKey,
        child:  Container(
          padding: const EdgeInsets.all(20.0),
          child: Column(
            children: [
              height,
              const SizedBox(height: 10.0,),
              splitLine,
              const SizedBox(height: 40.0,),
              weight,
              const SizedBox(height: 10.0,),
              splitLine,
              const SizedBox(height: 30.0,),
              standardTip,
              const SizedBox(height: 40.0,),
              calculateButton,
            ],
          ),
        )
    );

底部区域

底部使用的是Table表格进行布局,TableRow为行,TableCell为列,也可不使用TableCell进行布局,可输入自己需要的内容组件

Widget standardTable = Container(
      padding: const EdgeInsets.all(20.0),
      child: Table(
        border: TableBorder.all(
            color: Colors.black,
            width: 1.0,
            style: BorderStyle.solid,
            borderRadius: const BorderRadius.all(Radius.circular(5.0))
        ),
        children: [
          TableRow(
              decoration: const ShapeDecoration(
                  color: Colors.green,
                  shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.only(
                        topLeft: Radius.circular(5),
                        topRight: Radius.circular(5),
                      ),
                  ),
              ),
              children: [
                TableCell(child: Container(
                    padding: const EdgeInsets.all(10.0),
                    child: Center(child: Text('BMI值',style: getTextStyle(14.0, Colors.white, FontWeight.normal),),))
                ),
                TableCell(child: Container(
                    padding: const EdgeInsets.all(10.0),
                    child: Center(child: Text('身体状况',style: getTextStyle(14.0, Colors.white, FontWeight.normal),),))
                )
              ]
          ),
          TableRow(
              children: [
                TableCell(child: Container(
                    padding: const EdgeInsets.all(7.0),
                    child: Center(child: Text('<18.5',style: getTextStyle(12.0, Colors.grey, FontWeight.normal),),))
                ),
                TableCell(child: Container(
                    padding: const EdgeInsets.all(7.0),
                    child: Center(child: Text('偏瘦',style: getTextStyle(12.0, Colors.grey, FontWeight.normal),),))
                ),
              ]
          ),
          TableRow(
              children: [
                TableCell(child: Container(
                    padding: const EdgeInsets.all(7.0),
                    child: Center(child: Text('18.5~23.9',style: getTextStyle(12.0, Colors.grey, FontWeight.normal),),))
                ),
                TableCell(child: Container(
                    padding: const EdgeInsets.all(7.0),
                    child: Center(child: Text('正常',style: getTextStyle(12.0, Colors.grey, FontWeight.normal),),))
                ),
              ]
          ),
          TableRow(
              children: [
                TableCell(child: Container(
                    padding: const EdgeInsets.all(7.0),
                    child: Center(child: Text('24~27.9',style: getTextStyle(12.0, Colors.grey, FontWeight.normal),),))
                ),
                TableCell(child: Container(
                    padding: const EdgeInsets.all(7.0),
                    child: Center(child: Text('偏胖',style: getTextStyle(12.0, Colors.grey, FontWeight.normal),),))
                ),
              ]
          ),
          TableRow(
              children: [
                TableCell(child: Container(
                    padding: const EdgeInsets.all(7.0),
                    child: Center(child: Text('>=28',style: getTextStyle(12.0, Colors.grey, FontWeight.normal),),))
                ),
                TableCell(child: Container(
                    padding: const EdgeInsets.all(7.0),
                    child: Center(child: Text('肥胖',style: getTextStyle(12.0, Colors.grey, FontWeight.normal),),))
                ),
              ]
          ),
        ],
      ),
    );

页面组合

然后将上面三个区域进行组合

return Container(
      child: Column(
        children: [
          topArea,
          const SizedBox(height: 10.0,),
          centerArea,
          const SizedBox(height: 40.0,),
          standardTable,
        ],
      ),
    );

BMI计算

  • BMI = 体重 / 身高的平方
  • 身高标准体重 = 身高 - 105
    每一个Text使用变量作为内容展示,然后修改其内容之后,使用setState进行值刷新
 ///BMI计算
  void BMICalculate(String sHeight,String sWeight){
    if(sHeight.isEmpty || sWeight.isEmpty){
      showFailedToast('身高或体重不能为空');
      return;
    }
    //bmi计算
    double dHeight = double.parse(sHeight) ;
    double dWeight = double.parse(sWeight);
    double bmiValue = dWeight / ((dHeight / 100)*(dHeight / 100));
    //身体状况计算
    String condition = "NaN";
    if(bmiValue < 18.5){
      condition = '偏瘦';
    }else if(bmiValue >= 18.5 && bmiValue < 23.9){
      condition = '正常';
    }else if(bmiValue >= 23.9 && bmiValue < 27.9){
      condition = '偏胖';
    }else{
      condition = '肥胖';
    }
    //标准体重计算 身高-105
    double standard = dHeight - 105;
    //刷新数据
    setState(() {
      ///保留一位小数
      bmi = bmiValue.toStringAsFixed(1);
      body = 'body:$condition';
      standardWeight = '身高标准体重:${standard.toStringAsFixed(1)}';
    });
    print('【计算结果】:$bmi');
  }

Toast弹窗

效果

导入依赖

pubspec.yaml文件中导入如下第三方包

fluttertoast: ^8.1.1

封装

Web和APP有一些地方不一样,例如背景颜色,web需要单独进行设立,如下所示

///web端的位置和背景颜色需要重新设置,如webPosition| webBgColor
 void showSuccessToast(String text) {
  Fluttertoast.showToast(
      msg: text,
      toastLength: Toast.LENGTH_SHORT,
      gravity: ToastGravity.TOP,
      backgroundColor: Colors.green,
      fontSize: 14.0,
      webPosition: 'center',
      webBgColor: 'linear-gradient(0deg,#37ecba 0%, #72afd3 100%)',
  );
}

  void showFailedToast(String text) {
    Fluttertoast.showToast(
      msg: text,
      toastLength: Toast.LENGTH_SHORT,
      gravity: ToastGravity.TOP,
      backgroundColor: Colors.red,
      fontSize: 14.0,
      webPosition: 'center',
        webBgColor: 'linear-gradient(0deg,#f43b47 0%, #453a94 100%)'
    );
  }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/26961.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Unity ECS实例:制作俯视角射击游戏!

目录 创建主角 3&#xff1a;主角移动和摄像机跟随 4&#xff1a;实现敌人角色 5&#xff1a;子弹&#xff0c;死亡&#xff0c;机器人 6&#xff1a;粒子与音效 这次我们来使用Unity ECS系统制作一个俯视角度的射击游戏。虽然现在网上有不少ECS的资料和项目&#xff0c;但…

(十二)Spring IoC注解式开发

文章目录回顾注解注解怎么定义&#xff0c;注解中的属性怎么定义&#xff1f;元注解Target注解Retention注解注解怎么使用&#xff1f;通过反射机制怎么读取注解&#xff1f;Spring注解原理声明Bean的注解Spring注解的使用第一步&#xff1a;加入aop的依赖第二步&#xff1a;在…

1.3 c++虚基类的用途以及内存模型

1.3 虚基类 1.3.1 虚基类(菱形继承)的语法实现 对于如下的继承体系&#xff0c;定义了一个公共基类A。类B和类C都由类A公有派生&#xff0c;类D由类B和类C公有派生。 其示例代码如下所示&#xff0c;这段代码的45行是无法通过编译器的&#xff0c;这即是多重继承存在的一个问…

十二、组合API(2)

本章概要 响应式 API reactive() 方法watchEffect() 方法解构响应性状态深入 watchEffect()refreadonlycomputedwatch 11.3 响应式 API Vue 3.0 的核心功能主要是通过响应式 API 实现的&#xff0c;组合 API 将他们公开为独立的函数。 11.3.1 reactive() 方法 reactive()…

基于物联网的自动灌溉系统的设计与实现

本设计是基于物联网的自动灌溉系统&#xff0c;主要实现以下功能&#xff1a; 1&#xff0c;OLED显示温湿度和土壤温湿度&#xff1b; 2&#xff0c;可通过继电器实现自动灌溉和自动加热的功能&#xff1b; 3&#xff0c;通过lora构建自组网&#xff0c;进行主从机间的数据传输…

正点原子 核心板IMX6ULL IIC RTC驱动 PCF8563

目录前言IIC RTC PCF8563硬件使用IIC设备地址配置 menuconfig 自带PCF8563驱动修改设备树dtb编写应用App测试前言 此篇基于学完【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.6 后&#xff0c;使用核心板进行自行设置。 IIC RTC PCF8563硬件使用 Imx6ul内部的RTC时钟不是很准…

VMware Workstation虚拟机网络相关配置

1、网络配置 1.1、方式一&#xff1a;配置文件 配置文件&#xff1a;网络参数之IP地址与子网掩码、网关地址、DNS 1.1.1、删除旧网卡配置文件 rm -rf /etc/sysconfig/network-scripts/ifcfg-* 1.1.2、grub内核引导程序&#xff0c;定义网卡重新命名规则 vim /etc/default/…

若依vue ruoyi-vue ant design版本使用

若依vue默认是使用element ui的&#xff0c;但是现在大部分项目都用ant design&#xff0c;ant design的组件也比element多&#xff0c;所以最近有想更改成ant design。网上搜了一下&#xff0c;已经有现成的了。 RuoYi-Antdv https://gitee.com/fuzui/RuoYi-Antdv RuoYi-Ant…

【scala】第二章——Scala 变量和数据类型

文章目录1 注释2 变量和常量&#xff08;重点&#xff09;3 标识符的命名规范4 字符串输出5 键盘输入6 数据类型&#xff08;重点&#xff09;7 整数类型&#xff08;Byte、Short、Int、Long&#xff09;8 浮点类型&#xff08;Float、Double&#xff09;9 字符类型&#xff08…

1秒钟搞懂tee和vim文件的使用命令(超级详细)

1秒钟搞懂tee和vim文件的使用命令&#xff08;超级详细&#xff09;一&#xff0c;tee的具体使用1&#xff0c;tee用来显示屏幕并且保存在文件中2&#xff0c;&#xff08;|&#xff09;管道符用来覆盖上一文件内容3&#xff0c;-a用来追加文件内容二&#xff0c;vim的命令模式…

[附源码]计算机毕业设计JAVA教室用电控制系统

[附源码]计算机毕业设计JAVA教室用电控制系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybati…

如何把图片文字转换成文字?图片转文字方法推荐

我们在上课的时候&#xff0c;常常会跟不上老师的板书&#xff0c;这时候我们就会对一些来不及记录的板书&#xff0c;拍成图片保存下来&#xff0c;等到课后再进行整理。可是当图片积累的过多的时候&#xff0c;再一张一张的进行抄写&#xff0c;就会很浪费时间和精力了。但其…

诚邀莅临 | 天奥智能参展第86届中国国际医疗器械博览会

11月23-26日&#xff0c;第86届中国国际医疗器械博览会&#xff08;CMEF&#xff09;在深圳国际会展中心&#xff08;宝安新馆&#xff09;隆重举办。本届大会以“创新科技、智领未来”为主题&#xff0c;吸引了超过4000家国内外医疗器械、医用耗材、医疗机器人等企业参会。 南…

机器学习参数|数学建模|自相关性

目录 1.定义和影响 1.1自相关性产生的原因 1.2自相关的后果 2.减小影响方法 2.1如何判断数据存在自相关性 a.用相关计量软件 b.Durbin-Watson Statistics(德宾-瓦特逊检验) c.Q-Statistics 以(box-pierce)- Eviews(7th version第七版本)为例子 2.2如何减弱模型的自相关…

pytorch使用GPU加速--windows11,GTX1650Super

使用的都是anaconda创建的环境 1.软件准备 下载cuda 查看自己的显卡驱动–进入NVIDIA的控制面板 然后根据显卡驱动下载对映的cuda 查看的网址 下载cuda的网址 下载cuDNN NVIDIA cuDNN是用于深度神经网络的GPU加速库。它强调性能、易用性和低内存开销。 cudnn下载网址 这个下…

使用CAPL 内置函数 memcpy 和memcmp 处理数组的若干问题

&#x1f345; 我是蚂蚁小兵&#xff0c;专注于车载诊断领域&#xff0c;尤其擅长于对CANoe工具的使用&#x1f345; 寻找组织 &#xff0c;答疑解惑&#xff0c;摸鱼聊天&#xff0c;博客源码&#xff0c;点击加入&#x1f449;【相亲相爱一家人】&#x1f345; 玩转CANoe&…

树状数组学习

树状数组简介 树状数组&#xff0c;用于维护和查询前缀和&#xff0c;与线段树功能类似。树状数组代码短&#xff0c;常数和空间小&#xff0c;时间复杂度小&#xff0c;所以这也是一个十分优秀的算法。 设a[i]a[i]a[i]为原数组上的点&#xff0c;s[i]s[i]s[i]为树状数组中各点…

WordPress管理仪表板:在15分钟内成为WordPress专家

WordPress管理仪表板是内容管理系统 (CMS)的核心和灵魂。在这里&#xff0c;您可以监督网站的各个方面&#xff0c;从配置基本设置到发布内容、安装插件和主题等等。如果您不熟悉 WordPress 管理仪表板&#xff0c;您将很难管理网站。 了解如何使用仪表板比您想象的要容易。所有…

PixiJs学前篇(三):Canvas基础【下篇】

前言 在上一篇文章 PixiJs学前篇&#xff08;二&#xff09;&#xff1a;Canvas基础【中篇】 中我们了解了Canvas的基本绘制形状&#xff0c;接下来我们看一下如何在 Canvas 中绘制文本。 绘制文本 文本的绘制也是 Canvas 中也是比较常见的&#xff0c;在 Canvas 的绘制中&a…

STC51单片机36——51单片机简单分两路控制步进电机

按键控制步进电机正反转一定设置的角度&#xff0c;比如一圈360度&#xff0c;按一次30度&#xff0c;一起12档。分两路控制&#xff0c;4个加减按键&#xff0c;一个按键控制复位&#xff0c;每路控制输出tb6600驱动器驱动两个42电机同步。同时数码管显示出来每次按键加减后的…