Flutter圈子Flutter中文社区Flutter

Flutter新人实战—从0开始开发一个DIY活动记录应用(三)

2018-11-03  本文已影响5人  走路不穿鞋oO

上篇文章我们基本介绍了如何分析布局一个应用的整体框架,以及介绍了不带数据传递的不同页面之间的导航。
今天我们开始对页面要展示的内容进行实现,很显然今天涉及的就是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,然后自己实现一下吧。

上一篇下一篇

猜你喜欢

热点阅读