Flutter新人实战—从0开始开发一个DIY活动记录应用(三)基础UI控件绘制页面

版权声明:本文为本人原创文章,未经本人允许不得转载。
上篇文章我们基本介绍了如何分析布局一个应用的整体框架,以及介绍了不带数据传递的不同页面之间的导航。
今天我们开始对页面要展示的内容进行实现,很显然今天涉及的就是Flutter的各类控件了。

数据模型建立

在界面ui之前呢,我们先把活动项目的数据属性先建立起来,在后面的内容我们会用到。
在lib目录下新建文件夹model,用于存放数据模型,新建diy_project.dart文件:

image.png

完成数据属性的说明:
diy_project.dart

/*
diy项目类,说明diy项目的对象属性
*/

class DiyProject {
  int _id; //项目id
  String _name; //项目名字
  String _date; //项目时间
  String _place; //项目地点
  String _contact; //项目联系人
  String _imagePath; //项目照片地址

  int _singlePrice; //项目单价
  int _nums; //项目份数
  int _totalAmount; //项目总价
  int _itemCost; //物料成本
  int _laborCost; //人员成本
  int _profit; //项目利润

  bool _isCheckOut; //钱款是否结清

  //活动项目构造函数
  DiyProject(
    this._name,
    this._date,
    this._place,
    this._contact,
    this._imagePath,
    this._singlePrice,
    this._nums,
    this._totalAmount,
    this._itemCost,
    this._laborCost,
    this._profit,
    this._isCheckOut,
  );

  /*
  下面是获取活动项目各属性值得方法
  */
  String get name => _name;
  String get date => _date;
  String get place => _place;
  String get contact => _contact;
  String get imagePath => _imagePath;

  int get id => _id;
  int get singlePrcie => _singlePrice;
  int get nums => _nums;
  int get totalAmount => _totalAmount;
  int get itemCost => _itemCost;
  int get laborCost => _laborCost;
  int get profit => _profit;
  bool get isCheckOut => _isCheckOut;
}

然后我们在home_page文件中初始化一组项目数据,用于后面的数据展示,代码如下:
home_page.dart

//初始化三个项目数据
  List<DiyProject> _diyProjects = [
    new DiyProject('多肉种植', '2018-11-2', '万达广场', '苏苏', 'images/4.jpg', 30, 50,
        1500, 500, 300, 700, false),
    new DiyProject('彩绘尤克里里', '2018-10-22', '寰宇城', '盼盼', 'images/2.jpg', 20, 30,
        600, 500, 500, 1500, false),
    new DiyProject('小饼干制作', '2018-9-15', '滨江新城', '磊磊', 'images/5.jpg', 40, 50,
        2000, 600, 200, 800, false),
  ];

UI绘制

数据模型属性我们已经准备完毕,下面我们开始一步步实现首页的展示效果
我们要实现的首页展示效果如下:


首页.PNG

简单分析以后我们可以看得出首先这是一个可以滚动的ListView,里面包含的是一个个的Card,Card里对应的是项目活动的属性(展示照片、名称、时间、地点等等)。这些属性又是按照一定的方向进行排列的,其实很多教程和文章里都有说到如何分析一个页面的布局,那要点就是一个字:拆

我们对这个card进行拆解:

1、card里是一个Colum的垂直排列
2、从上往下分别是图片、名称日期组合、联系人地点组合、金额
3、其中名称日期和联系人地点是一个Row控件实现的横向排列

下面我们边撸码边看效果:
首先为了整体代码文件的清晰整洁,我们在lib下新建ui文件夹,在ui文件夹里新建diy_list_show.dart

image.png

然后在文件中根据上面拆解的结构绘制ui控件:
diy_list_show.dart

import 'package:activity_record/model/diy_project.dart';
import 'package:flutter/material.dart';

class DiyListShow extends StatefulWidget {
  //将项目对象作为参数配置给DiyListShow的构造函数
  DiyListShow({Key key, this.diyItem}) : super(key: key);
  DiyProject diyItem;
  @override
  State<StatefulWidget> createState() => new DiyListShowState();
}

class DiyListShowState extends State<DiyListShow> {
  @override
  Widget build(BuildContext context) {
    //card第一行时间和预留按钮菜单
    Widget _rowTime() {
      return new Container(
        //设置距离左边8.0的内间距
        padding: const EdgeInsets.only(left: 8.0),
        child: new Row(
          //表示两个子空间头尾分布
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: <Widget>[
            new Text(widget.diyItem.date),
            new IconButton(
              icon: new Icon(Icons.more_horiz),
              onPressed: () {},
            )
          ],
        ),
      );
    }

    //card第三行名称和地点
    Widget _rowNameAndPlace() {
      return new Container(
        padding: const EdgeInsets.all(8.0),
        child: new Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: <Widget>[
            new Text(widget.diyItem.name,
                style:
                    new TextStyle(fontSize: 17.0, fontWeight: FontWeight.bold)),
            new Text(widget.diyItem.place),
          ],
        ),
      );
    }

    //进行card里的内容组合
    Widget _diyContentShow() {
      return Container(
        height: 288.0,
        child: new Column(
          children: <Widget>[
            _rowTime(),
            //使用expanded将填充控件的剩余空间
            new Expanded(
                //flex代表这个控件在父控件里的范围比例,默认是1,这里表示在高度288的容器里,图片会填满剩余的所有空间
                flex: 3,
                child: new Image.asset(
                  widget.diyItem.imagePath,
                  fit: BoxFit.cover,
                  width: 400.0,
                )),
            _rowNameAndPlace(),
            new Padding(
              padding: const EdgeInsets.fromLTRB(8.0, 0.0, 8.0, 8.0),
              child: new Row(
                children: <Widget>[
                  new Text(
                    '${widget.diyItem.singlePrcie.toString()}元',
                    style: new TextStyle(
                        fontSize: 15.0,
                        color: Theme.of(context).primaryColor,
                        fontWeight: FontWeight.bold),
                  ),
                  new SizedBox(
                    width: 20.0,
                  ),
                  new Text(
                    '${widget.diyItem.nums.toString()}份',
                    style: new TextStyle(
                        fontSize: 15.0,
                        color: Theme.of(context).primaryColor,
                        fontWeight: FontWeight.bold),
                  )
                ],
              ),
            )
          ],
        ),
      );
    }

    //将整个项目展示内容包裹在card里
    return new Card(
      margin: const EdgeInsets.fromLTRB(18.0, 18.0, 18.0, 9.0), //设置外边距18
      //card形状设置顶部圆形弧度12,底部没有
      shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.vertical(top: Radius.circular(12.0))),
      //inkwell是一个带水波纹触摸效果的控件,预留点击回调作为以后点击响应事件
      child: new InkWell(
        onTap: () {},
        child: _diyContentShow(),
      ),
    );
  }
}

里面的主要知识点我进行了注释,细心的朋友可能发现了一个知识点——image.asset,下面介绍使用方法:

  1. 首先需要在lib同级新建图片文件夹images


    image.png
  2. 将想使用的图片拷贝到目录下
  3. pubsec.yaml文件里配置图片的位置引用
    引用方法如下:
    image.png

这样我们就能使用image.asset('图片地址')展示图片了。
Card的UI我们写完了,下面我们回到home_page.dart,修改body代码看看card得显示效果如何:
home_page.dart

body: new ListView.builder(
        itemCount: 3,
        itemBuilder: (context, index) {
          return new DiyListShow(
            diyItem: _diyProjects[index],
          );
        },
      ),

写完后可能发现DiyListShow()下面有警告,因为我们还没引用这个dart文件,所以在开头我们导入文件:
import 'package:activity_record/ui/diy_list_show.dart';包括以后在引用或使用其他dart文件里的方法内容的时候都要记得先导入需要引用的文件。
以上代码中ListView是列表滚动控件,他有两个构造函数,分别是ListView()和ListView.builder()
其中ListView()适合内容不多的情况使用,因为flutter会全部渲染完成后展现,如果是数据量很多或者无限数据的话就要使用ListView.builder(),这个构造方法是根据用户滚动的情况,实时渲染需要展现的数据,当滑出屏幕后就会回收对应的数据。

写了这么多,是时候看下效果了,UI界面的调整都是边看边改的,对于新人我们不可能一步到位直接写好,边写边热重载边修改非常关键,好了运行后效果如下:


image.png

image.png

感觉是不是还可以,哈哈 自恋下。可能有人觉得奇怪,这和上面开头的图的布局不一样啊,这是因为女王大人给我提了新的需求,她对之前的效果提出了修改意见,要知道用户的需求才是关键嘛,毕竟我们做完是给他们用的,所以我做了调整和之前的不一样了,不过只要你掌握了方法,无论怎么改我相信你都可以做出来的啦。

最后总结

今天我们主要介绍了flutter里的基础控件,虽然用到的不多,但是都是非常基础和常用的,包括listview、container、row、column、sizedbox、card、text、iconbutton、expanded、padding等等,每个控件里都有很多属性,对于新人来说不要记得那么多,主要记住每个控件常用的属性就可以啦,其他的后面再慢慢学习就好了。
试试看在每个内容前加上小的示意图标(比如在时间前加上代表时间的icon),美化整个card效果,动手试试吧!或者你也可以根据自己想要的样子设计一个展示UI,然后自己实现一下吧。

最后附上项目源码地址:https://gitee.com/xusujun33/activity_record_jia.git
项目持续更新中.......

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容