Flutter Widget 静态布局实战

Stella981
• 阅读 548

相关文章
Flutter 环境搭建以及填坑指南(Win10 系统且已有 Android 开发环境 )
Flutter 入门实现 ListView 列表页面以及收藏页面
Flutter Widget 静态布局实战
Flutter 容器类 Widget

前面两篇文章介绍了 Flutter win环境的安装,以及利用listview 实现了简单布局。(这篇文章篇幅有点长,读完大概需要8.88分钟)
Flutter 入门实现 ListView 列表页面以及收藏页面
Flutter 环境搭建以及填坑指南(Win10 系统且已有 Android 开发环境

这篇文章主要介绍以下内容:
1. ListView 能实现什么效果?
2. widget 如何添加到 ListView 中?
3. ListView 点击事件,单个 widget 点击事件
4. ( 重点 ) widget 如何垂直、水平摆放?
5. 图片、Icon、Text widget 的简单使用

在这篇文章Flutter 入门实现 ListView 列表页面以及收藏页面中虽然实现了一个列表,但是怎么实现的还没仔细研究,现在就先从研究 ListView的实现开始吧。

先看一下之前实现的效果:
Flutter Widget 静态布局实战
实现的代码主要是RandomWordsState类中的下面代码:

return new ListTile(
      // 单词布局
      title: new Text(
        pair.asPascalCase,
        style: _biggerFont,
      ),
      // 喜欢小心心布局
      trailing: new Icon(
        alreadySaved ? Icons.favorite : Icons.favorite_border,
        color: alreadySaved ? Colors.red : null,
      ),
      // ListView item 的点击事件
      onTap: () {
        // 通知框架状态已经改变
        setState(() {
          if (alreadySaved) {
            _saved.remove(pair);
          } else {
            _saved.add(pair);
          }
        });
      },
    );

从上面的代码中可以看出实现这个列表主要就是操作了 ListTile 这个 Widget,那么我们看看这个ListTile的构造方法都提供了上面功能吧!注释都写在代码中了~

/// Requires one of its ancestors to be a [Material] widget.
  const ListTile({
    Key key,
    // 在列表的左边添加的 widget(如文末图中的左边图片)
    this.leading,
    // 标题
    this.title,
    // 副标题
    this.subtitle,
    // 在列表的右边添加的 widget(如文末图中的右边心形 icon)
    this.trailing,
    // 如果 isThreeLine 为 true, subtitle 则不能为 null,默认为 false
    // 如果 副标题为空则列表平铺一行显示,如果 副标题 不为空,则副标题所占的布局是两行
    // 如果 isThreeLine = true 则副标题可以显示三行。
    this.isThreeLine = false,
    // bool 类型,默认为false ,如果为 true 则 ListTile 在垂直方向是密集型摆放
    //(具体效果待后面去实现,这里只是看了注释后的理解)
    this.dense,
    // 内容的边距
    this.contentPadding,
    // item 是否能点击
    this.enabled = true,
    // item 的点击事件
    this.onTap,
    // item 的长按事件
    this.onLongPress,
    // item 是否选中标记
    this.selected = false,
  }) 

flutter 的开发语言是dart,这个语言之前没学过,这里就先不深入学习了,网上有比较好的这个博主 恋猫月亮
写的系列的文章写的很好。我这里就只写实现上面图片中展示的效果。

1. ListView 能实现什么效果?

ListView 不仅可以实现列表布局,还可以实现 Android 中的 ScrollView 的功能。关于 滚动的 widget 还有其他的实现,可参考**可滚动Widget简介**

实现列表功能,如果是符合ListTile的样式,直接使用ListTile实现很方便。(目前还没学到如何实现多布局,后面学习再写一篇)

实现ScrollView功能,直接在build方法的body中添加我们的 widget。伪代码如下:

定义了一个DetailScreen详情页面,继承了StatelessWidget,在build方法中返回了页面的内容:appBar 是标题栏,body 是显示的内容

class DetailScreen extends StatelessWidget {
 // Declare a field that holds the pair
 final WordPair pair;

 // In the constructor, require a pair
 DetailScreen({Key key, @required this.pair}) : super(key: key);

 @override
 Widget build(BuildContext context) {
 return new Scaffold(
      appBar: new AppBar(
        // 接收传递过来的单词做标题名字
        title: new Text("${pair.asPascalCase}"),
      ),
      // 使用 ListView 做滚动列表
      body: new ListView(  
        children: [
          // 显示网络图片
          new Image.asset(
            'images/wali.jpg',
            width: 600.0,
            height: 240.0,
            fit: BoxFit.cover,
          ),
          // 标题行(文末有实现效果)
          titleSection,
          // 按钮行(文末有实现效果)
          buttonSection,
          // 描述文本(文末有实现效果)
          textSection,
        ],
      ),
    );
  }
}

2. widget 如何添加到 ListView 中?

上面的伪代码中在构建一个有状态的widget的时候会重写 build方法,在该方法中的 body返回我们实现的 widget即可。

3. ListView 点击事件,单个 widget 点击事件

如果ListView使用ListTile实现列表的话,直接使用ListTile中的 onTap实现列表点击效果。如果不是用ListTile实现,那就使用单个widget的点击事件吧。

widget的如果有onTap方法可以直接调用该方法即可实现,如果没有该方法,则需要使用GestureDetector来实现点击效果,例如上图中的心形喜欢点击事件,伪代码实现如下:

关于GestureDetector可参考该文章 手势识别GestureDetector

trailing: new GestureDetector(
        // 心形喜欢 icon
        child: new Icon(
          alreadySaved ? Icons.favorite : Icons.favorite_border,
          color: alreadySaved ? Colors.red : null,
        ),
        // 点击事件
        onTap: (){
          // 通知框架状态已经改变
          setState(() {
            if (alreadySaved) {
              _saved.remove(pair);
            } else {
              _saved.add(pair);
            }
          });
        },
      ),

4. widget 如何垂直、水平摆放?

最常见的布局模式之一是垂直或水平排列widget。在Flutter可以使用行Row水平排列widget,并使用列Column垂直排列widget。 同时,每个孩子本身可以是一个Row或一个Column,依此类推。以下示例显示如何在行或列内嵌套行或列。

通过下面两张图片可以学到在实现布局时如何拆分:
参考链接 widget 布局
Flutter Widget 静态布局实战
Flutter Widget 静态布局实战

在控制行或列对齐其子项时使用mainAxisAlignment( 主轴 ) 和crossAxisAlignment( 横轴 ) 属性来。 对于行(Row)来说,**主轴是水平方向,横轴垂直方向。**对于列(Column)来说,主轴垂直方向,横轴水平方向。
Flutter Widget 静态布局实战
Flutter Widget 静态布局实战
MainAxisAlignmentCrossAxisAlignment 类提供了很多控制对齐的常量.
MainAxisAlignment

  • center → const MainAxisAlignment :子 widget在主轴方向上居中显示

  • end → const MainAxisAlignment :子 widget在主轴方向上居右边显示,如果是水平方向,那么由 TextDirection 来决定end是在左边(ltr)还是在右边(rtl)。如果是竖直方向,那么由 VerticalDirection 来决定end是在上边(up)还是在下边(down)

  • start → const MainAxisAlignment:子 widget在主轴方向上居左边显示,同理 end

  • spaceAround → const MainAxisAlignment:子widget中的第一个和最后一个widget距离边的距离是它与中间的距离的一半。(这里比较抽象,后期实现效果了会顺带讲解)

  • spaceBetween → const MainAxisAlignment:子widget中的第一个和最后一个贴边,剩余的子widget将中间的空间平分。

  • spaceEvenly → const MainAxisAlignment:子widget 将布局空间完全平分
    Flutter Widget 静态布局实战

  • values → const List<MainAxisAlignment>:根据值得大小来分配空间,值越大空间分配越多。

CrossAxisAlignment 属性相同的基本和上面介绍的一样,就不赘述了。

Expanded widget

Expanded widget,可以将widget的大小设置为适和行或列 Expanded有个属性flex(弹性系数),默认情况下,每个widget的弹性系数为1,也就是会铺满布局。

例如实现:三张图片水平铺满屏幕,即可使用Expanded包裹Image然后设置flex:1,不设置也行,因为默认flex就是1
Flutter Widget 静态布局实战

伪代码如下:

body: new Center(
  child: new Row(
    crossAxisAlignment: CrossAxisAlignment.center,
    children: [
      new Expanded(
        child: new Image.asset('images/pic1.jpg'),
      ),
      new Expanded(
        child: new Image.asset('images/pic2.jpg'),
      ),
      new Expanded(
        child: new Image.asset('images/pic3.jpg'),
      ),

聚集 widgets

默认情况下,行或列沿着其主轴会尽可能占用尽可能多的空间,但如果要将孩子紧密聚集在一起,可以将mainAxisSize设置为MainAxisSize.min

例如实现:五个星形图标图标紧凑在一起。
Flutter Widget 静态布局实战
伪代码如下:

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    var packedRow = new Row(
      mainAxisSize: MainAxisSize.min,
      children: [
        new Icon(Icons.star, color: Colors.green[500]),
        new Icon(Icons.star, color: Colors.green[500]),
        new Icon(Icons.star, color: Colors.green[500]),
        new Icon(Icons.star, color: Colors.black),
        new Icon(Icons.star, color: Colors.black),
      ],
    );

  // ...
}

5. 图片、Icon、Text widget 的简单使用

这些都是基础控件使用起来很简单的,可查看这个文档介绍:**基础 Widget**

在学习完上面的内容我们可以实现出目前的样式了:
Flutter Widget 静态布局实战

实现列表功能,以及一个可滚动的详情页面,顶部的标题是 listview 传递过去的单词。

文章篇幅过长了,这里就不介绍上图的实现过程了,源码地址如下
觉得还凑合的给个star,好让我继续坚持写下去~
源码地址

看源码或者上文中不理解的可以联系我,我会知无不言的。

本文完。

本文同步分享在 博客“_龙衣”(CSDN)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
Java获得今日零时零分零秒的时间(Date型)
publicDatezeroTime()throwsParseException{    DatetimenewDate();    SimpleDateFormatsimpnewSimpleDateFormat("yyyyMMdd00:00:00");    SimpleDateFormatsimp2newS
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
Java日期时间API系列36
  十二时辰,古代劳动人民把一昼夜划分成十二个时段,每一个时段叫一个时辰。二十四小时和十二时辰对照表:时辰时间24时制子时深夜11:00凌晨01:0023:0001:00丑时上午01:00上午03:0001:0003:00寅时上午03:00上午0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
2个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这