• flutter系列之:flutter中常用的Stack layout详解


    简介

    对于现代APP的应用来说,为了更加美观,通常会需要用到不同图像的堆叠效果,比如在一个APP用户背景头像上面添加一个按钮,表示可以修改用户信息等。

    要实现这样的效果,我们需要在一个Image上面堆叠其他的widget对象,flutter为我们提供了这样的一个非常方便的layout组件叫做Stack,今天和大家一起来聊一聊Stack的使用。

    Stack详解

    我们先来看下Stack的定义:

    class Stack extends MultiChildRenderObjectWidget 
    

    Stack继承自MultiChildRenderObjectWidget,表示在stack中可以render多个child widget对象。

    因为Stack中的child是重叠关系,所以需要对child进行定位,根据定位的不同Stack中的child可以分为两种类型,分别是positioned和non-positioned。

    所谓positioned,是指child widget被包装在Positioned中。什么是Positioned呢?

    Positioned是专门用来定位Stack中的child位置的一个widget。所以Positioned必须用在Stack中,并且Positioned和Stack的路径之间只能存在StatelessWidget或者StatefulWidget这两种widget。

    如果一个对象被包含在Positioned中,那么这个对象就是一个Stack中的positioned对象。

    Positioned中除了封装的child之外,还有6个属性,如下所示:

      const Positioned({
        Key? key,
        this.left,
        this.top,
        this.right,
        this.bottom,
        this.width,
        this.height,
        required Widget child,
      })
    

    这六个属性分别是left,top,right,bottom,width和height。其中left,top,right,bottom分别表示到左,顶,右,底的距离,这个距离是相对stack来说的。而width和height则表示的是Positioned的宽度和高度。

    事实上,使用left和right可以定义出width,使用top和bottom可以定义出height。

    如果在一个轴方向的三个值都不存在,那么会使用Stack.alignment来定位子元素。

    如果六个值都不存在,那么这个child就是一个non-positioned的child。

    对于non-positioned的child,是通过Stack的alignment来进行布局的,默认情况下是按top left corners进行布局的。

    Stack的属性

    我们接下来看一下Stack中有哪些属性,下面是Stack的构造函数:

      Stack({
        Key? key,
        this.alignment = AlignmentDirectional.topStart,
        this.textDirection,
        this.fit = StackFit.loose,
        @Deprecated(
          'Use clipBehavior instead. See the migration guide in flutter.dev/go/clip-behavior. '
          'This feature was deprecated after v1.22.0-12.0.pre.',
        )
        this.overflow = Overflow.clip,
        this.clipBehavior = Clip.hardEdge,
        List children = const [],
      })
    

    可以看到Stack中有alignment,textDirection,fit,overflow和clipBehavior这几个属性。

    首先来看alignment,这里的alignment是一个AlignmentGeometry对象,主要用来布局non-positioned children。

    AlignmentGeometry中有两个需要设置的属性,分别是start和y。

    start表示的是横线定位范围,它的取值比较奇怪,-1表示的是start side的边缘位置,而1表示的是end side的边缘位置。如果取值超过了这个范围,则表示对应的位置超过了边缘位置。

    start的位置跟TextDirection是相关联的,如果TextDirection的值是ltr,也就是说从左到右排列,那么start就在最左边,如果TextDirection的值是rtl,也就是说从右到左排列,那么start就是在最右边。

    有横向位置就有纵向位置,这个纵向位置用y来表示,它的正常取值范围也是-1到1,当然你也可以超出这个范围。

    为了用户更加方便的使用AlignmentGeometry,AlignmentGeometry提供了一些便捷的方法,如topStart,topCenter,topEnd等,大家可以自行选取。

    接下来的属性是textDirection,textDirection是一个TextDirection对象,它有两个值,分别是rtl和ltr,在讲解alignment的时候,我们已经提到过textDirection,它会影响alignment中横向的布局。

    接下来是StackFit类型的fit属性,StackFit有三个值,分别是loose,expand和passthrough。

    loose表示的是一个松散结构,比如Stack规定的size是300x500,那么它的child的宽度可以从0-300,child的高度可以从0-500.

    expand表示是一个扩充的效果,比如Stack规定的size是300x500,那么它的child的宽度就是300,child的高度就是500.

    passthrough表示传递给stack的限制会原封不动的传递给他的child,不会进行任何修改。

    overflow表示children超出展示部分是否会被剪切。不过这个属性已经是Deprecated,flutter推荐我们使用clipBehavior这个属性来代替。

    clipBehavior是一个Clip对象,它的默认值是Clip.hardEdge。其他的几个值还有none,hardEdge,antiAlias和antiAliasWithSaveLayer。

    none表示不进行任何裁剪,hardEdge的裁剪速度最快,但是精确度不高。antiAlias速度比hardEdge慢一点,但是有光滑的边缘。antiAliasWithSaveLayer是最慢的,应该很少被使用。

    Stack的使用

    有了上面的讲解,接下来我们看一下Stack的具体使用。

    在我们这个例子中,我们在Stack中设置一个背景图片,然后在图片上叠加一个文本。

    那么应该怎么实现呢?

    首先我们需要设置Stack的alignment方式,我们希望文本和图片的中心重合,也就是说把文字放在图片中间,我们将Stack的alignment设置为Alignment.center。

    接下来是一个背景图片,因为原始图片是一个正方形的图片,我们需要对图片进行裁剪成圆形,这里使用一个非常方便的类CircleAvatar来创建圆形的图标:

     const CircleAvatar(
              backgroundImage: AssetImage('images/head.jpg'),
              radius: 100,
            ),
    

    上面的代码能够创建一个半径是100的圆。

    然后是文本的创建,可以给Text设置文本内容和对应的style:

    Text(
                '编辑',
                style: TextStyle(
                  fontSize: 20,
                  fontWeight: FontWeight.bold,
                  color: Colors.white,
                ),
              )
    

    然后把Text封装在Container中,并使用BoxDecoration给他指定一个背景:

    Container(
              decoration: const BoxDecoration(
                color: Colors.green,
              ),
              child: const Text(
                  ...
    

    最后将上面的代码组合起来就是我们最后的Stack:

     Widget build(BuildContext context) {
        return Stack(
          alignment: Alignment.center,
          children: [
            const CircleAvatar(
              backgroundImage: AssetImage('images/head.jpg'),
              radius: 100,
            ),
            Container(
              decoration: const BoxDecoration(
                color: Colors.green,
              ),
              child: const Text(
                '编辑',
                style: TextStyle(
                  fontSize: 20,
                  fontWeight: FontWeight.bold,
                  color: Colors.white,
                ),
              ),
            ),
          ],
        );
    

    运行生成的界面如下:

    总结

    以上就是Stack的使用,通过堆叠组件,我们可以实现很多炫酷的功能。

    本文的例子:https://github.com/ddean2009/learn-flutter.git

    更多内容请参考 http://www.flydean.com/11-flutter-ui-layout-stack/

    最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!

    欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!

  • 相关阅读:
    SQL监控工具
    1542. 找出最长的超赞子字符串 哈希+状态压缩
    【附源码】Python计算机毕业设计社区老人健康服务跟踪系统
    2022/6/27 Quartz(定时任务)讲解+入门案例
    基于JAVA天津城建大学校友录管理系统计算机毕业设计源码+系统+mysql数据库+lw文档+部署
    ValueAnimator的一些骚玩法
    天堂2游戏出错如何解决
    3D模型格式转换工具HOOPS Exchange助力Halocline开发VR
    matplotlib 笔记: contourf & contour
    【智能家居入门2】(MQTT协议、微信小程序、STM32、ONENET云平台)
  • 原文地址:https://www.cnblogs.com/flydean/p/16711713.html