GXU-ACM
请选择 进入手机版 | 继续访问电脑版

广西大学ACM-ICPC竞赛论坛

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 189|回复: 7

基于Flutter框架开发的整数分区计算器

[复制链接]

15

主题

31

帖子

144

积分

版主

Rank: 7Rank: 7Rank: 7

积分
144
QQ
发表于 2019-7-13 09:47:33 | 显示全部楼层 |阅读模式
之前经常使用命令行工具DiskPart或Windows安装程序setup.exe给硬盘分区,这些工具没有整数分区计算功能。需要调整分区容量的时候往往也需要计算。此时如果掏出手机利用移动app计算要比在PE里面计算方便一些,所以早有想法开发这样一款整数分区计算的工具。由于本人正在学习Flutter这款跨平台app开发框架,程序也是用Flutter实现的。源代码:
https://github.com/zhaojingyits/partition_format_calculator

效果图:

计算器

计算器

常用容量

常用容量
回复

使用道具 举报

15

主题

31

帖子

144

积分

版主

Rank: 7Rank: 7Rank: 7

积分
144
QQ
 楼主| 发表于 2019-7-13 09:51:17 | 显示全部楼层
首先建立calchelper.dart,存储计算整数分区容量的代码。
对于FAT32格式:
应分配MB数=(分区GB数-1)×4+1024×分区GB数
也就是说,如果你要在FAT32格式的硬盘上分出一个10 GB的硬盘,那么:
你应该分配的MB数=(10-1)×4+1024×10=10276 MB
这样你就可以得到整数的10 GB分区了。
对于NTFS格式:
硬盘一般有255磁头,63扇区,故每柱面大小为:
512byte x 255 x 63=8225280bytes =7.84423828125 MB
如果要分10 GB,那么要10x1024 MB=10240 MB
需要柱面数为10240÷7.84423828125=1305.416744475568004979769685652
取整数既为1306个柱面
应分MB数为1306x7.84423828125=10244.5751953125 MB
不管小数点后面几位都进1,也就是10245 MB,系统也就认为是10.00 GB了。
据此可以写出如下代码:
int calculateNTFS(int targetGB) {
  const double size=7.84423828125;
  return ((1024*targetGB/size).ceil()*size).ceil();
}
int calculateFAT(int targetGB) =>(targetGB-1)*4+1024*targetGB;
回复 支持 反对

使用道具 举报

15

主题

31

帖子

144

积分

版主

Rank: 7Rank: 7Rank: 7

积分
144
QQ
 楼主| 发表于 2019-7-13 09:58:24 | 显示全部楼层
建立文件calc.dart,在calc.dart写入计算器页面布局代码。核心代码:
Widget build(BuildContext context)=>Container(
//设置Container和ListView容器是为了让页面空间不够的时候可以滑动
    alignment: Alignment.center,
        padding: EdgeInsets.all(16.0),
        child: ListView(
//ListView是纵向布局的容器
          children: <Widget>[
//[]表示List,Dart内置的类似于数组的数据结构
    const SizedBox(height: 10),//表示与上面分隔一定距离
    Text('目标文件系统:',textScaleFactor: 1.2),//文本对象,设置了放大比例1.2
    Row(
//Row是横向布局
      children: <Widget>[
//以下两个是Radio单选框
        Flexible(child: RadioListTile<int>(groupValue: isntfs,value: 1,title: Text('NTFS'), onChanged: (value) {_setNTFS();_setted();},),),
        Flexible(child: RadioListTile<int>(groupValue: isntfs,value: 0,title: Text('FAT32'), onChanged: (value) {_setFAT();_setted();},),)
      ],
    ),
    const SizedBox(height: 10),
    Text('目标分区容量:',textScaleFactor: 1.2),
    const SizedBox(height: 10),
    TextField(
//输入框
      keyboardType: TextInputType.number,//输入内容是数字
      decoration: InputDecoration(
//设置装饰
        contentPadding: EdgeInsets.all(10.0),//定位
        icon: Icon(Icons.list),//图标,图标取自Flutter内置的Material图标
        labelText: '请输入分区容量(GB)',//提示文字
        helperText: '仅支持整数的GB值'
      ),
      onChanged: _doCalculate,//设置文本改变的时候需要执行的方法
      autofocus: false,//不自动设置为focus
    ),
    const SizedBox(height: 10),
    Divider(),//分割线
    Text('整数分区值(MB)为:',textScaleFactor: 1.2),
    const SizedBox(height: 10),
    Center(child:Text('$calcResult MB',textScaleFactor: 2.5,textAlign: TextAlign.center,))//通过textAlign设置居中
  ],
  ));
回复 支持 反对

使用道具 举报

15

主题

31

帖子

144

积分

版主

Rank: 7Rank: 7Rank: 7

积分
144
QQ
 楼主| 发表于 2019-7-13 10:05:47 | 显示全部楼层
继续看calc.dart,这是其它部分的代码:
首先为了使用material的元素需要引入material.dart,然后为了计算,需要import刚才写的calchelper.dart
import 'package:flutter/material.dart';
import 'calchelper.dart';
为了进行状态管理,实时更新页面内容,页面设置成有状态的StatefulWidget。应用较简单,实际上也可以设置成StatelessWidget。
class CalculatePage extends StatefulWidget {
  State<StatefulWidget> createState() {
    return new CalculatePageState();//return new根据dart语法都可以省略。new可以直接省略,return可以用aaa()=>b来代替aaa(){return b;},下面build方法都用到了
  }
}
class CalculatePageState extends State<CalculatePage> {
//以下几个变量用来执行计算和存储
  String calcResult='0';
  int isntfs=1;
//名称前面带_的是内部变量或内部方法,相当于private。这里不太规范
  int _tempGB;
  void _doCalculate(String str){
    setState(() {
//setState是为了更改内部变量的同时更新相应的widget。如果不包在setState里面,虽然变量的值修改了但是显示不出来,因为没有更新
      _tempGB=int.parse(str);//更新_tempGB
      _setted();
    });
  }
  void _setted(){
    setState(() {
//这是一个三目运算,第一行是个判断,返回bool
      calcResult=isntfs==1
    ?calculateNTFS(_tempGB).toString()
    :calculateFAT(_tempGB).toString();
    });
  }
  void _setNTFS(){
    setState(() {
      isntfs=1;
    });
  }
  void _setFAT(){
    setState(() {
      isntfs=0;
    });
  }
  Widget build(BuildContext context)=>Container(
//此处代码在上一楼
  )
}
回复 支持 反对

使用道具 举报

15

主题

31

帖子

144

积分

版主

Rank: 7Rank: 7Rank: 7

积分
144
QQ
 楼主| 发表于 2019-7-13 10:09:26 | 显示全部楼层
建立list.dart显示常用容量。
import 'package:flutter/material.dart';
import 'calchelper.dart';

class ListPage extends StatelessWidget{
  Widget build(BuildContext context)=>Container(
//return的省略写法
        padding: EdgeInsets.all(16.0),
        child: ListView(
          children: <Widget>[DataTable(
//数据表对象
            columnSpacing: 30.0,
    columns: <DataColumn>[
//表头
      DataColumn(label:  Text('整数容量(GB)'),),
      DataColumn(label:  Text('NTFS容量(MB)'),),
      DataColumn(label:  Text('FAT32容量(MB)'),),
    ],
    rows: <DataRow>[
    DataRow(cells: [DataCell(Text("10")),DataCell(Text(calculateNTFS(10).toString())),DataCell(Text(calculateFAT(10).toString())),]),
//中间省略。如果用一个builder批量生成会更合适,但是暂时没找到好办法,这样也够用了。
DataRow(cells: [DataCell(Text("2048")),DataCell(Text(calculateNTFS(2048).toString())),DataCell(Text(calculateFAT(2048).toString())),]),
    ],
  )]));
}
回复 支持 反对

使用道具 举报

15

主题

31

帖子

144

积分

版主

Rank: 7Rank: 7Rank: 7

积分
144
QQ
 楼主| 发表于 2019-7-13 10:15:52 | 显示全部楼层
本帖最后由 三次根号a 于 2019-7-13 10:22 编辑

接下来看main.dart。示例里面注释太多,删掉,然后重新编写这个main.dart,实现主页的页面切换。
import 'package:flutter/material.dart';
import 'calc.dart';
import 'list.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
//MaterialApp是一个综合各种Material元素的Widget,用来构建完整应用界面
      title: '整数分区计算器',//这里的title是任务管理页面的应用名
      theme: ThemeData(
        primarySwatch: Colors.blue,。。默认主题
      ),
      home: MainPage(),//主页入口
    );
  }
}
class MainPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
        debugShowCheckedModeBanner: false, home: new MainPageWidget());
//加这一层可以去掉debug的标签,可以去掉,本文比较粗糙,还可以优化
  }
}

class MainPageWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return new MainPageState();
//同样是状态管理
  }
}

class MainPageState extends State<MainPageWidget> {
//控制底栏切换
  int _tabIndex = 0;
  var tabImages;
  var appBarTitles = ['计算器', '常用容量'];
  var _pageList;
  Text getTabTitle(int curIndex) {
    if (curIndex == _tabIndex) {
      return new Text(appBarTitles[curIndex],
          style: new TextStyle(fontSize: 14.0, color: const Color(0xff1296db)));
    } else {
      return new Text(appBarTitles[curIndex],
          style: new TextStyle(fontSize: 14.0, color: const Color(0xff515151)));
    }
  }


  void initData() {

    _pageList = [
      new CalculatePage(),
      new ListPage(),
    ];
  }

  @override
  Widget build(BuildContext context) {
    //初始化数据
    initData();
    return Scaffold(
//Scaffold也是综合的Widget,用来构建Material页面,包括顶栏AppBar,主题Body,底栏BottomNavigationBar等
      appBar: AppBar(title: Text('整数分区计算器'),actions: <Widget>[
//IconButton是图标样式的按钮,图标同样来自Flutter内置Material组件
        IconButton(icon: Icon(Icons.info_outline),onPressed:  (){ showAboutDialog(
//点击按钮显示关于窗口
          context: context,
          applicationIcon: Icon(Icons.list),
          applicationName: '整数分区计算器',
          applicationVersion: "1.0",
          children: [
            Text('联系方式:zhaojingyits@foxmail.com'),
            Divider(),
            Text('采用Flutter技术构建。')
          ]
        );}
        ,)
      ],),
        body: _pageList[_tabIndex],
        bottomNavigationBar: new BottomNavigationBar(
//底栏
          items: <BottomNavigationBarItem>[
            new BottomNavigationBarItem(
                icon: Icon(Icons.equalizer), title: getTabTitle(0)),
            new BottomNavigationBarItem(
                icon: Icon(Icons.list), title: getTabTitle(1)),
          ],
          type: BottomNavigationBarType.fixed,
          //默认选中首页
          currentIndex: _tabIndex,
          iconSize: 24.0,
          //点击事件
          onTap: (index) {
            setState(() {
              _tabIndex = index;
            });
          },
        ));
  }
}
回复 支持 反对

使用道具 举报

15

主题

31

帖子

144

积分

版主

Rank: 7Rank: 7Rank: 7

积分
144
QQ
 楼主| 发表于 2019-7-13 10:18:54 | 显示全部楼层
在这以后app基本上写好了,同时有如下几点还可以微调:
AndroidManifest.xml里面要把app的启动器名称改成中文;
pubspec.yaml里面可能还有不需要的插件;
用自己的图标替换应用默认图标;
设置混淆、ABI、Bundle、签名等。
一切就绪后通过flutter build apk命令生成apk。
回复 支持 反对

使用道具 举报

15

主题

31

帖子

144

积分

版主

Rank: 7Rank: 7Rank: 7

积分
144
QQ
 楼主| 发表于 2019-7-13 10:20:51 | 显示全部楼层
由于同时编译了armv7和armv8的abi,以及多出了一些不需要的iOS控件,应用体积较大。由于没有x86的abi,在模拟器运行比较慢。但是在案后极端可以感觉到运行很快,说明flutter达到了宣称的接近原生的速度体验,且可以实现复杂的应用功能。
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|gxuacm  

GMT+8, 2019-10-24 05:22 , Processed in 0.133641 second(s), 25 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表