blog icon indicating copy to clipboard operation
blog copied to clipboard

[译] Flutter: 图解 BoxDecoration

Open SunshowerC opened this issue 6 years ago • 0 comments

  • 基本介绍
  • 属性
    • color (背景颜色)
    • gradient (背景渐变色)
      • LinearGradient (线性渐变)
        • LinearGradient.colors
        • begin (默认 Alignment.centerLeft)
        • end (默认 Alignment.centerRight)
      • tileMode 平铺模式
        • TileMode.clamp (默认)
        • TileMode.mirror
        • TileMode.repeated
      • stops
        • stops 默认值
        • 自定义 stops 值
      • RadialGradient (径向渐变)
    • image
      • DecorationImage.alignment
      • DecorationImage.centerSlice
      • DecorationImage.colorFilter
      • DecorationImage.fit
        • BoxFit.contain
        • BoxFit.cover
        • BoxFit.fill
        • BoxFit.contain
        • BoxFit.fitHeight
        • BoxFit.fitWidth、
        • BoxFit.none
        • BoxFit.scaleDown
      • DecorationImage.repeat
        • ImageRepeat.noRepeat
        • ImageRepeat.repeat
        • ImageRepeat.repeatX
        • ImageRepeat.repeatY
      • DecorationImage.matchTextDirection
    • border
      • Border.all
      • Border Class
      • BorderDirectional
    • borderRadius
      • BorderRadius.all
      • BorderRadius.circular
      • BorderRadius.horizontal
      • BorderRadius.vertical
      • BorderRadius.only
    • boxShadow
    • shape
    • padding

基本介绍

BoxDecoration 类提供了几种方式来绘制一个容器,主要用于绘制更加复杂的样式。

容器有 border(边框),body(主体),可能还有 boxShadow(阴影)

容器的形状可以是圆形或者矩形,如果是矩形,可以设置 borderRadius 控制角的弧度。

容器主体背景分为多个层级,最底层是填充满容器的背景颜色,再上一层是填充容器的渐变色,最后是图像,由 DecorationImage 类控制,

也就是说背景优先级: 图像 > 渐变色 > 纯色

属性

color (背景颜色)

new Center(
  child: new Container(
    decoration: new BoxDecoration(
      color: Colors.purple,
    ),
    child: new FlutterLogo(
      size: 200.0,
    )
  ),
);

PS: Container 部件的 color 属性不能和 decoration 属性同时使用

事实上,

Container(
  color: Colors.purple
)

是以下 decoration 的简写:

Container(
  decoration: new BoxDecoration(color: Colors.purple)
)

gradient (背景渐变色)

LinearGradient (线性渐变)

LinearGradient.colors

线性渐变颜色列表

begin (默认 Alignment.centerLeft)

线性渐变的起始点

end (默认 Alignment.centerRight)

线性渐变的终止点

Center(
  child: new Container(
    decoration: new BoxDecoration(
      color: Colors.purple,
      gradient: new LinearGradient(
        colors: [Colors.red, Colors.cyan],
        begin: Alignment.centerRight,
        end: Alignment.centerLeft
      ),
    ),
    child: new FlutterLogo(
      size: 200.0,
    )
  ),
);

=

由于是线性渐变,所以

    begin: Alignment.centerRight,
    end: Alignment.centerLeft
    begin: Alignment.topRight,
    end: Alignment.topLeft
    begin: Alignment.bottomRight,
    end: Alignment.bottomLeft

这几种都是等价的

tileMode 平铺模式

定义了在 指定的 begin 和 end 之外的区域,渐变色应该如何渲染

TileMode.clamp (默认)

TileMode.clamp 表明在 begin - end 区域外,渐变色应该保持 colors 列表内指定的颜色。

new Center(
  child: new Container(
    decoration: new BoxDecoration(
      color: Colors.purple,
      gradient: new LinearGradient(
        colors: [Colors.red, Colors.cyan],
        begin: Alignment.centerRight,
        end: new Alignment(0.8, 0.0),
        tileMode: TileMode.clamp
      ),
    ),
    child: new FlutterLogo(
      size: 200.0,
    )
  ),
);

TileMode.mirror

在 begin - end 区域外,应该保持镜像的渐变色。

new Center(
  child: new Container(
    decoration: new BoxDecoration(
      color: Colors.purple,
      gradient: new LinearGradient(
        colors: [Colors.red, Colors.cyan],
        begin: Alignment.centerRight,
        end: new Alignment(0.8, 0.0),
        tileMode: TileMode.mirror
      ),
    ),
    child: new FlutterLogo(
      size: 200.0,
    )
  ),
);

TileMode.repeated

在区域外重复进行渐变色的渲染

new Center(
  child: new Container(
    decoration: new BoxDecoration(
      color: Colors.purple,
      gradient: new LinearGradient(
        colors: [Colors.red, Colors.cyan],
        begin: Alignment.centerRight,
        end: new Alignment(0.8, 0.0),
        tileMode: TileMode.repeated
      ),
    ),
    child: new FlutterLogo(
      size: 200.0,
    )
  ),
);

stops

  • 值为 0.0 ~ 1.0 之间的 的列表
    • 如果赋值了,stops 值列表长度必须和 colors 列表长度相等。
  • 值必须为升序

stops 默认值

如果没有给 stops 赋值, 渐变色区域将会根据颜色数量均匀分割。 即:

  gradient: new LinearGradient(
    colors: [Colors.red, Colors.cyan, Colors.yellow ],
    begin: Alignment.centerRight,
    end: Alignment.centerLeft,
    // stops 默认值为
    // stops: [0, 0.5, 1]
  ),

自定义 stops 值

new Center(
  child: new Container(
    decoration: new BoxDecoration(
      color: Colors.purple,
      gradient: new LinearGradient(
        colors: [Colors.red, Colors.cyan, Colors.purple, Colors.lightGreenAccent],
        begin: Alignment.centerRight,
        end: Alignment.centerLeft,
        tileMode: TileMode.clamp,
        stops: [0.3, 0.5, 0.6, 0.7]
      ),
    ),
    child: new FlutterLogo(
      size: 200.0,
    )
  ),
);

这里表示:假定宽度长 100%,从右往左进行 Colors.red(红), Colors.cyan(青), Colors.purple(紫), Colors.lightGreenAccent(绿) 这 4 种颜色的渐变。

  • 其中从右往左 30% 的点是 红色,50% 的点是青色,60% 的点是紫色,70% 的点是 绿色
  • 根据上述配置,所以从右往左,0~30%是纯红色,30% ~ 50% 是 红到青的渐变色,50% ~ 60% 是青到紫的渐变色,60%~70% 是紫到绿的渐变色,70%~100% 是纯绿色。

RadialGradient (径向渐变)

RadialGradient 有 5 个主要属性:

  • center 默认值:Alignment.center
    径向渐变的中心,值为 Alignment
  • radius 默认值 0.5
    径向渐变的半径,即如果容器半径是 200px,那么 radius=0.5,默认 绘制 半径为 100px 的径向渐变圆。
  • colors
    同上述的线性渐变,不再赘述
  • stops
    同上述的线性渐变,不再赘述
  • tileMode
    同上述的线性渐变,不再赘述
new Center(
  child: new Container(
    decoration: new BoxDecoration(
      color: Colors.purple,
      gradient: new RadialGradient(
        colors: [Colors.red, Colors.cyan, Colors.purple, Colors.lightGreenAccent],
        center: Alignment(-0.7, -0.6),
        radius: 0.2,
        tileMode: TileMode.clamp,
        stops: [0.3, 0.5, 0.6, 0.7]
      ),
    ),
    child: new FlutterLogo(
      size: 200.0,
    )
  ),
);

image

绘制图片背景,图片通常是 AssetImage (应用配置的图片资源),或者是 NetworkImage (网络图片资源)

new Center(
  child: new Container(
    decoration: new BoxDecoration(
      color: Colors.purple,
      gradient: new RadialGradient(
        colors: [Colors.red, Colors.cyan, Colors.purple, Colors.lightGreenAccent],
        center: Alignment(0.0, 0.0),
        radius: 0.5,
        tileMode: TileMode.clamp,
        stops: [0.3, 0.5, 0.9, 1.0]
      ),
      image: new DecorationImage(
          image: new NetworkImage("http://jlouage.com/images/author.jpg")
      )
    ),
    child: new FlutterLogo(
      size: 200.0,
    )
  ),
);

可以看到,由于图片优先级比较高,渲染在最上层,图片背景绘制覆盖了渐变背景和 纯色背景。

DecorationImage.alignment

同 Container 部件的 alignment,不再赘述

DecorationImage.centerSlice

centerSlice 决定以哪一种方式,按区域对图像进行缩放处理。

例如,我们有一张图片,可以设置其四个角的区域不进行缩放,其他区域进行缩放(这么说可能有点抽象,以下实例再详细说明)

centerSlice 属性的值为 Rect 类,也就是一个矩形。

  • Rect.fromLTWH(double left, double top, double width, double height)

假如我们有一张这样尺寸的图片

当我们的 centerSlice 值为 Rect.fromLTWH(50.0, 50.0, 220.0, 90.0) 时,即

new Center(
    child: new Container(
      decoration: new BoxDecoration(
        image: new DecorationImage(
            image: new AssetImage('assets/images/9_patch_scaled_320x190.png'),
            centerSlice: new Rect.fromLTWH(50.0, 50.0, 220.0, 90.0),
            fit: BoxFit.fill,
        )
      ),
      child: new Container(
        //color: Colors.yellow,
        width: 110.0,
        height: 110.0,
      )
    ),

  );

得到的效果如下(将 320 x 190 尺寸大小的图片拉伸在 110 x 110 的容器中,其中图片四个角 50 x 50 的区域不进行拉伸,其他区域进行拉伸):

扩大容器的大小后:

new Center(
    child: new Container(
      decoration: new BoxDecoration(
        image: new DecorationImage(
            image: new AssetImage('assets/images/9_patch_scaled_320x190.png'),
            centerSlice: new Rect.fromLTWH(50.0, 50.0, 220.0, 90.0),
            fit: BoxFit.fill,
        )
      ),
      child: new Container(
        //color: Colors.yellow,
        width: 350.0,
        height: 450.0,
      )
    ),

  );

得到的效果如下(将 320 x 190 尺寸大小的图片拉伸在 350 x 450 的容器中,其中图片四个角 50 x 50 的区域不进行拉伸,其他区域进行拉伸):

这个属性的效果一般比较少用,其中的值大家可以随便测试看看效果。

DecorationImage.colorFilter

给背景图片加上颜色滤镜。值一般为 ColorFilter.mode(颜色, 混合模式)

我们将给以下图片 加上粉色滤镜colorFilter: new ColorFilter.mode(Colors.red.withOpacity(0.5), BlendMode.color), 并以不同的模式进行混合。

new Center(
    child: new Container(
      width: double.infinity,
      height: double.infinity,
      color: Colors.white,
      child: new Container(
        decoration: new BoxDecoration(
          image: new DecorationImage(
              image: new AssetImage('assets/images/JL-Logo-empty.png'),
              colorFilter: new ColorFilter.mode(Colors.red.withOpacity(0.5), BlendMode.color),
          )
        ),
      ),
    ),
  );
  • BlendMode.color
    提取指定颜色的色调和饱和度,给目标图片着色
  • BlendMode.darken
    通过从每个颜色通道中选择最低值来合成源图像和目标图像。
  • BlendMode.clear
  • BlendMode.src
  • BlendMode.colorBurn
  • BlendMode.colorDodge
  • BlendMode.difference
  • BlendMode.dst
  • BlendMode.dstATop
  • BlendMode.dstIn
  • BlendMode.dstOut
  • BlendMode.dstOver
  • ......

滤镜的混合模式很多,这里就不一一解读了,有兴趣的可以看原文详细解读

DecorationImage.fit

如何渲染图像到盒子中,(PS: 不同于 DecorationImage.centerSlice 作用于图片本身,DecorationImage.fit 是作用于画布的)
值为 BoxFit 的枚举值

Center(
    child: new Container(
      width: double.infinity,
      height: double.infinity,
      color: Colors.white,
      child: new Container(
        decoration: new BoxDecoration(
          image: new DecorationImage(
              image: new NetworkImage('http://jlouage.com/images/author.jpg'),
              fit: BoxFit.contain
          )
        ),
      ),
    ),
  );

BoxFit.contain

图片尽可能大,并且容器依然包含整个图片资源

以下图片为同一图片资源在不同尺寸的容器中的展示方式。

BoxFit.cover

图片尽可能小,且必须覆盖满整个容器。

BoxFit.fill

通过拉伸图片来覆盖满整个容器

BoxFit.contain

BoxFit.fitHeight

确保图片资源的全部高度都可见,无论图片资源的宽度是不是溢出容器

BoxFit.fitWidth、

类似上,确保图片资源的全部宽度都可见,无论图片资源的高度是不是溢出容器

BoxFit.none

居中对齐图片资源,不缩放大小,丢弃容器之外的部分。

BoxFit.scaleDown

类似于 BoxFit.contain,居中对齐图片资源,并在必要的时候,缩小图片资源以确保整个资源都在容器啊,

DecorationImage.repeat

渲染图片到图片大小之外的容器其他区域。
值为 ImageRepeat 枚举值

ImageRepeat.noRepeat

其他区域保持透明

Center(
    child: new Container(
      width: double.infinity,
      height: double.infinity,
      color: Colors.white,
      child: new Container(
        decoration: new BoxDecoration(
          image: new DecorationImage(
              image: new AssetImage('assets/images/JL-Logo-150.png'),
              repeat: ImageRepeat.noRepeat
          )
        ),
      ),
    ),
  );

ImageRepeat.repeat

在x和y方向上重复图像,直到填充满容器。

ImageRepeat.repeatX

在x轴上重复图像,直到水平填充满容器。

ImageRepeat.repeatY

在y轴上重复图像,直到垂直填充满容器。

DecorationImage.matchTextDirection

是否以 TextDirection 的方向渲染图片,值为 true/false;

如果是 true。 那么在 TextDirection.ltr 的环境下,图片将会以左上角为原点开始绘制(一般情况下的绘制方向),如果是在TextDirection.rtl 的环境下, 图片将会以右上角为原点开始绘制。

border

在背景颜色(color),渐变色背景(gradient)或图像背景(image)上方绘制的边框。
值为 Border 类,Border.allBorderDirectional

Border.all

设置4边的边框:

参数如下:

  • color: 边框颜色
  • width: 边框打下
  • style: 边框样式,值为 BorderStyle.solid 或者 BorderStyle.none
new Center(
    child: new Container(
      width: 200.0,
      height: 200.0,
      color: Colors.white,
      child: new Container(
        decoration: new BoxDecoration(
          border: new Border.all(
            color: Colors.green,
            width: 5.0,
            style: BorderStyle.solid
          ),
          image: new DecorationImage(
              image: new AssetImage('assets/images/JL-Logo-150.png'),
          )
        ),
      ),
    ),
  );

Border Class

指定边的边框, 参数分别为 top, bottom, right, left; 值为 BorderSide 类(参数同Border.all).

border: new Border(
    top: new BorderSide(
      color: Colors.green,
      width: 5.0,
      style: BorderStyle.solid
    ),
  ),

BorderDirectional

BorderDirectional 类似 Border , 同样有 4 个参数(top, bottom, start, end),其中的 start/end 对应Borderleft/right

border: new BorderDirectional(
    top: new BorderSide(
      color: Colors.green,
      width: 5.0,
      style: BorderStyle.solid
    ),
    start: new BorderSide(
        color: Colors.green,
        width: 5.0,
        style: BorderStyle.solid
    ),
  ),
  ima

borderRadius

设置圆角。(仅在 shape: BoxShape.rectangle 时有效)。

值可以为: BorderRadius.all, BorderRadius.only, BorderRadius.circular, BorderRadius.horizontal, BorderRadius.vertical.

BorderRadius.all

new Center(
    child: new Container(
      width: 200.0,
      height: 200.0,
      color: Colors.white,
      child: new Container(
        decoration: new BoxDecoration(
          border: new Border.all(
              color: Colors.green,
              width: 5.0,
              style: BorderStyle.solid
          ),
          borderRadius: new BorderRadius.all(new Radius.circular(20.0)),
          image: new DecorationImage(
              image: new AssetImage('assets/images/JL-Logo-150.png'),
          )
        ),
      ),
    ),
  );

BorderRadius.circular

BorderRadius.circular(20) 等价于 BorderRadius.all(new Radius.circular(20.0))

BorderRadius.horizontal

设置水平方向一边的边框

borderRadius: new BorderRadius.horizontal(
    left: new Radius.circular(20.0),
    //right: new Radius.circular(20.0),
  ),

BorderRadius.vertical

设置垂直方向一边的边框

borderRadius: new BorderRadius.vertical(
    top: new Radius.circular(20.0),
    //bottom: new Radius.circular(20.0),
  ),

BorderRadius.only

指定角的圆角弧度

borderRadius: new BorderRadius.only(
    // 设置椭圆
    topLeft: new Radius.elliptical(40.0, 10.0),,
    //topRight: new Radius.circular(20.0),
    //bottomRight: new Radius.circular(20.0),
    bottomLeft: new Radius.circular(20.0),
  ),

boxShadow

在容器后设置阴影。
值是一个 list , 也就是说可以设置多个阴影的值

值为 BoxShadow 类, 参数为:

  • color : 阴影颜色
  • offset: 阴影的偏移值
  • blurRadius: 高斯模糊值
  • spreadRadius: 模糊扩散的偏移范围

仅设置偏移值

new Center(
    child: new Container(
      width: 200.0,
      height: 200.0,
      color: Colors.white,
      child: new Container(
        decoration: new BoxDecoration(
          color: Colors.white,
          border: new Border.all(
              color: Colors.green,
              width: 5.0,
              style: BorderStyle.solid
          ),
          borderRadius: new BorderRadius.only(
            topLeft: new Radius.elliptical(40.0, 10.0),
            bottomLeft: new Radius.circular(20.0),
          ),
          boxShadow: [
            new BoxShadow(
              color: Colors.red,
              offset: new Offset(20.0, 10.0),
            )
          ],
          image: new DecorationImage(
              image: new AssetImage('assets/images/JL-Logo-150.png'),
          )
        ),
      ),
    ),
  );


设置高斯模糊值

boxShadow: [
    new BoxShadow(
      color: Colors.red,
      offset: new Offset(20.0, 10.0),
      blurRadius: 20.0,
    )
  ],


高斯模糊的扩散范围 spreadRadius

boxShadow: [
    new BoxShadow(
      color: Colors.red,
      offset: new Offset(20.0, 10.0),
      blurRadius: 20.0,
      spreadRadius: 40.0
    )
  ],


多个阴影值(由外向内)

boxShadow: [
    new BoxShadow(
      color: Colors.red,
      offset: new Offset(20.0, 10.0),
      blurRadius: 20.0,
      spreadRadius: 40.0
    ),
    new BoxShadow(
        color: Colors.yellow,
        offset: new Offset(20.0, 10.0),
        blurRadius: 20.0,
        spreadRadius: 20.0
    ),
    new BoxShadow(
        color: Colors.green,
        offset: new Offset(10.0, 5.0),
        blurRadius: 20.0,
        spreadRadius: 5.0
    )
  ],

shape

形状,只有矩形和圆形两种

  • BoxShape.rectangle(默认)
  • BoxShape.circle
new Center(
    child: new Container(
      width: 200.0,
      height: 200.0,
      child: new Container(
        decoration: new BoxDecoration(
          color: Colors.white,
          border: new Border.all(
              color: Colors.green,
              width: 5.0,
              style: BorderStyle.solid
          ),
          boxShadow: [
            new BoxShadow(
              color: Colors.red,
              offset: new Offset(20.0, 10.0),
              blurRadius: 20.0,
              spreadRadius: 40.0
            )
          ],
          shape: BoxShape.circle,
          image: new DecorationImage(
              image: new AssetImage('assets/images/JL-Logo-150.png'),
          )
        ),
      ),
    ),
  );

padding

同 Container 中的 padding 值,参考 Flutter: 图解 Container 部件

SunshowerC avatar Feb 18 '19 07:02 SunshowerC