Flutter之BoxDecoration用法详解

18,184 阅读21分钟

前言

相关文章:Flutter学习目录

github地址:Flutter学习

文章结构

  • Gradient Property
  • TileMode property
  • RadialGradient
  • Image Property
  • centerSlice Property
  • ColorFilter Property
  • fit Property
  • repeat Property
  • matchTextDirection Property
  • Border Property
  • borderRadius Property
  • boxShadow Property
  • shape Property
  • Padding Property

介绍:

BoxDecoration类提供了多种绘制盒子的方法。

这个盒子有边框、主体、阴影组成。

盒子的形状可能是圆形或者长方形。如果是长方形,borderRadius属性可以控制边界的圆角大小。

盒子的主体部分在layers层绘制。盒子的最底层是color层,在color层上面是gradient层color层gradient层都是填充整个盒子。最后是image层,它的对齐方式右DecorationImage类控制。

边框在主体上层绘制,阴影在主体下层绘制。


这里我们在一个空的container中,使用boxDecoration的color属性 代码如下:

//Colors
class BoxDecoration_Colors_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        decoration: BoxDecoration(
          color: Colors.purple
        ),
        child: FlutterLogo(
          size: 200.0,
        ),
      ),
    );
  }
}

效果图如下:

图1 Colors使用

注意: 如果你使用了decoration属性,就不能再使用color属性。这个color参数只是“decoration: new BoxDecoration(color:color)”的简写。因此,以下代码运行会提示错误:

child: Container(
        //二者不能同时出现
        decoration: BoxDecoration(
          color: Colors.purple
        ),
        color: Colors.green,
      ),

一、Gradient Property

在填充整个盒子模型时,会使用到渐变属性。

如果使用了渐变属性,color属性将不会有效果。

这个渐变在image图层下面绘制。

渐变属性的值可以是LinearGradient类或者RadialGradient类。

这里将详细介绍LinearGradient和RadialGradient。

LinearGradient有5个重要属性:

  • begin(渐变开始的位置)
  • end(渐变结束的位置)
  • colors(渐变颜色,是数组)
  • stops(值列表,装有0.0到1.0的数值)
  • tileMode(渐变平铺模式,指定在开始和结束以外的区域平铺模式)

代码如下:

//Gradient Property
class Gradient_Property_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        decoration: BoxDecoration(
          color: Colors.purple,
          gradient: LinearGradient(
              colors: [Colors.red, Colors.cyan],
          )
        ),
        child: FlutterLogo(
          size: 200.0,
        ),
      ),
    );
  }
} 

效果图如下:

图2 Gradient属性

如果我们没有添加begin和start属性,这个渐变将会使用默认属性,从左向右绘制。


这里我们尝试添加begin和end属性,你将使用Alignment类的两个属性。 代码如下:

//Gradient Property
//begin和end属性
class Gradient_Property_beginAndEnd_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        decoration: BoxDecoration(
            color: Colors.purple,
            gradient: LinearGradient(
              colors: [Colors.red, Colors.cyan],
              begin: Alignment.centerRight,
              end: Alignment.centerLeft
            ),
        ),
        child: FlutterLogo(
          size: 200.0,
        ),
      ),
    );
  }
}

效果图如下:

图3 Gradient属性

记住它是一个线性渐变。因此如果begin是bottomRight,end是bottomLeft,那么这个渐变将从右向左绘制。以下设置效果一样:

begin: Alignment.centerRight & end: Alignment.centerLeft

begin: Alignment.topRight & end: Alignment.topLeft


同样你可以使用Alignment类中的坐标系属性X和Y。 更多关于Alignment类详情查看Flutter之Container用法详解。 代码如下;

//Gradient Property
//begin和end属性
class Gradient_Property_beginAndEnd_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        decoration: BoxDecoration(
            color: Colors.purple,
            gradient: LinearGradient(
              colors: [Colors.red, Colors.cyan],
              begin: Alignment.centerRight,
              //end: Alignment.centerLeft
              end: Alignment(-1.0, -1.0)//效果同上
            ),
        ),
        child: FlutterLogo(
          size: 200.0,
        ),
      ),
    );
  }
}

效果图如下:

图4 Gradient属性


二、TileMode property

在开始和结束之前,此渐变应如何平铺该区域以外的平面。

TileMode值:

  • TileMode.clamp
  • TileMode.mirror
  • TileMode.repeated

图5 TileMode数值

TileMode.clamp 是默认的渲染方式

代码如下:

//TileMode property
//TileMode.clamp
class TileMode_Clamp_Property_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        decoration: BoxDecoration(
          color: Colors.purple,
          gradient: LinearGradient(
              colors: [Colors.red, Colors.cyan],
              begin: Alignment.centerRight,
              end: Alignment(0.8,0.0),
              tileMode: TileMode.clamp
          )
        ),
        child: FlutterLogo(
          size: 200.0,
        ),
      ),
    );
  }
}

效果图如下:

图6 TileMode.clamp属性


TileMode.mirror

代码如下:

//TileMode property
//TileMode.mirror
class TileMode_Mirror_Property_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        decoration: BoxDecoration(
          color: Colors.purple,
          gradient: LinearGradient(
              colors: [Colors.red, Colors.cyan],
              begin:Alignment.centerRight,
              end: Alignment(0.8,0.0),
              tileMode: TileMode.mirror
          ),
        ),
        child: FlutterLogo(
          size: 200.0,
        ),
      ),
    );
  }
}

效果图如下:

图7 TileMode.mirror


TileMode.repeated

代码如下:

//TileMode property
//TileMode.repeated
class TileMode_Repeated_Property_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        decoration: BoxDecoration(
          color: Colors.purple,
          gradient: LinearGradient(
              colors: [Colors.red, Colors.cyan],
              begin: Alignment.centerRight,
              end: Alignment(0.8,0.0),
              tileMode: TileMode.repeated
          )
        ),
        child: FlutterLogo(
          size: 200.0,
        ),
      ),
    );
  }
}

效果图如下:

图8 TileMode.repeated


Stops

一个从0.0到1.0的值列表,数值表示梯度方向上的分割比例。

如果Stops不为空,那么它必须与colors中颜色个数保持一致,否则运行异常。

如果第一个数值不为0,此时会默认一个stop位置0.0,颜色和colors中第一个颜色相同。

如果最后一个数值不为1.0,此时会默认一个stop位置1.0,颜色和colors中最后一个颜色相同。

stops值列表中的数据必须是升序。如果stops值列表有一个数据小于前一个数据值,那么这个数据会被默认等于前面的数据值。

如果stops是空的,那么stops里面默认存放一组均匀分布的点,并且第一个点是0.0,最后一个点是1.0。

代码如下:

//Gradient Property
//Stops属性
class Stops_Property_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        decoration: BoxDecoration(
          color: Colors.purple,
          gradient: 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: FlutterLogo(
          size: 200.0,
        ),
      ),
    );
  }
}

效果图如下:

图9 stops属性


三、RadialGradient

径向渐变有5个重要属性

  • center(渐变的中心)
  • radius(渐变的半径,浮点型,具体数值需要乘以盒子的宽度)
  • colors(渐变颜色,是数组)
  • stops(值列表,装有0.0到1.0的数值)
  • tileMode(渐变平铺模式,指定在圆环以外的区域平铺模式)

代码如下:

//RadialGradient
class RadialGradient_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        decoration: BoxDecoration(
          color: Colors.purple,
          gradient: 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: FlutterLogo(
          size: 200.0,
        ),
      ),
    );
  }
}

效果图如下:

图10 RadialGradient

同线性渐变一样,Center属性用Alignment类取值,取值范围是0.0到1.0。

如果在宽度是200.0的盒子上绘制径向渐变,那么radius是0.5,就代表100.0。

图10


四、Image Property

在color层和gradient层上方绘制图像。image属性的值是DecorationImage类。

DecorationImage类包含以下属性:

image

这个图片被绘制到图层中。通常,这个图片将是AssetImage(应用程序内部提供的图片)或者NetworkImage(用于从网络获取的图片)。 代码如下:

//Image Property
class Image_Property_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        decoration: BoxDecoration(
          color: Colors.purple,
          gradient: 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: DecorationImage(
            image: NetworkImage("http://jlouage.com/images/author.jpg"),
        ),
      ),
      child: FlutterLogo(
        size: 200.0,
      ),
     ),
    );
  }
}

效果图如下:

图11 Image

从上面图片可以看出,这个图片是绘制在color层和gradient层上方。


五、centerSlice Property

centerSlice与Android Studio中的9补丁png相同。这是一种用于缩放图像的技术,使得4个角保持不缩放,但是四个边在一个轴上缩放,中间在两个轴上缩放。

图12 centerSlice Property

这个centerSlice类的数值是Rect类。我们需要从左边和顶边,宽度和高度构造一个矩形。 让我们开始了解我们图片的大小。

图13

Width = 320 & the Height = 190

我们需要使用Rect.fromLTWH(double left, double top, double width, double height)类来获取数据。

我们的centerSlice是图片中间的绿色矩形。要创建它,我们需要知道橙色矩形的宽度,把它放在左边的值和紫色矩形的高度,并把它作为最高值。

图14

Rect.fromLTWH(50.0, 50.0, double width, double height)

所以我们告诉Rect类从左边移动50,从图片顶部移动50,然后从上面标记的黄点开始绘制矩形。

图15

在上图中,矩形的宽度为220,高度为90,因此最终的类值应为Rect.fromLTWH(50.0, 50.0, 220.0, 90.0)

代码如下:

//centerSlice Property
//关联问题:
//https://github.com/flutter/flutter/issues/16098
class centerSlice_Property_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        decoration: BoxDecoration(
          image: DecorationImage(
              image: AssetImage("images/9_patch_scaled_320x190.jpeg"),
              centerSlice: new Rect.fromLTWH(50.0, 50.0, 220.0, 90.0),
              fit: BoxFit.fill,
          )
        ),
        child: Container(
          //color: Colors.yellow,
          width: 110.0,
          height: 110.0,
        ),
      ),
    );
  }
}

效果图如下:

图16

我们可以看出4个红色的区域没有缩放。现在增加container的子控件的宽和高。

代码如下:

//centerSlice Property
//关联问题:
//https://github.com/flutter/flutter/issues/16098
class centerSlice_Property_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        decoration: BoxDecoration(
          image: DecorationImage(
              image: AssetImage("images/9_patch_scaled_320x190.jpeg"),
              centerSlice: new Rect.fromLTWH(50.0, 50.0, 220.0, 90.0),
              fit: BoxFit.fill,
          )
        ),
        child: Container(
          //color: Colors.yellow,

          //width: 110.0,
          //height: 110.0,
          width: 350.0,
          height: 450.0,
        ),
      ),
    );
  }
}

效果图如下:

图17


六、ColorFilter Property

在绘制图像之前应用于图像的滤色器。这个属性值是 ColorFilter类,方法是ColorFilter.mode。

ColorFilter.mode()有两个参数,第一个是滤色镜,第二个是blend mode(混合模式)。

我们将会使用下面的图片,并且在上面应用不同的ColorFilter。

图18

BlendMode.src

我们将用Colors.red.withOpacity(0.5)和多种混合模式。下面我们将使用BlendMode.src。这将删除目标图像,仅绘制源图像。这里目标图像是image,源图像是Container(最里层的)。 代码如下:

//ColorFilter Property
class ColorFilter_Property_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: double.infinity,
        height: double.infinity,
        //color: Colors.white,
        color: Colors.grey,
        child: Container(
          decoration: BoxDecoration(
            image: DecorationImage(
                image:AssetImage("images/JL-Logo-empty.png"),
                colorFilter: ColorFilter.mode(Colors.red.withOpacity(0.5), BlendMode.src)
            ),
          ),
        ),
      ),
    );
  }
}

效果图如下:

图19 BlendMode.src

BlendMode.clear

现在将要使用BlendMode.clear。这将丢弃源图像和目标图像,不会留下任何内容。

效果图如下:

图20 BlendMode.clear


BlendMode.color

获取源图像的​​色调和饱和度以及目标图像的亮度。 效果是使用源图像为目标图像着色。 输出图像的不透明度的计算方法与srcOver相同。 在源图像中完全透明的区域从目的地获取其色调和饱和度。 简单来说,就是用当前Container颜色给image染色(通俗易懂)。 效果图如下:

图21 BlendMode.color


BlendMode.colorBurn

将目标的倒数除以源,并反转结果。 反转组件意味着完全饱和的通道(不透明的白色)被视为值0.0,通常被视为0.0(黑色,透明)的值被视为1.0。 这个说法有点太专业,自己都有点迷糊了!!!直接看效果吧。 效果图如下:

图22 BlendMode.colorBurn


BlendMode.colorDodge

将目标除以源的倒数。 反转组件意味着完全饱和的通道(不透明的白色)被视为值0.0,通常被视为0.0(黑色,透明)的值被视为1.0。 同样感觉一头雾水,看效果图吧!!! 效果图如下:

图23 BlendMode.colorDodge


BlendMode.darken

通过从每个颜色通道中选择最低值来合成源图像和目标图像。 输出图像的不透明度的计算方法与srcOver相同。 效果图如下:

图24 BlendMode.darken


BlendMode.difference

从每个通道的较大值中减去较小的值。 合成黑色没有效果;合成白色会反转另一幅图像的颜色。 输出图像的不透明度的计算方法与srcOver相同。 效果图如下:

图25 BlendMode.difference


BlendMode.dst

删除源图像,仅绘制目标图像。 从概念上讲,源图像被丢弃,保持目的地不变。 这对应于“目标”Porter-Duff运算符。 效果图如下:

图26 BlendMode.dst


BlendMode.dstATop

将目标图像合成到源图像上,但仅限于它与源重叠的位置。 这对应于“Destination atop Source”Porter-Duff运算符。 这本质上是dstOver运算符,但输出的不透明度通道设置为源图像的不透明度通道,而不是图像的不透明度通道的组合。 对于源位于顶部而非目标的变体,请参阅srcATop。 效果图如下:

图27 BlendMode.dstATop


BlendMode.dstIn

显示目标图像,但仅显示两个图像重叠的位置。 源图像未呈现,仅被视为蒙版。忽略源的颜色通道,只有不透明度才有效。 要显示源图像,请考虑srcIn。 要反转掩码的语义(仅显示目标所在的源,而不是缺少目标的位置),请考虑dstOut。 这对应于“源中的目的地”Porter-Duff运算符。 效果图如下:

图28 BlendMode.dstIn


BlendMode.dstOut

显示目标图像,但仅显示两个图像不重叠的位置。源图像未呈现,仅被视为蒙版。忽略源的颜色通道,只有不透明度才有效。 要显示源图像,请考虑srcOut。 要反转掩码的语义(仅显示源存在的目标,而不是缺少的位置),请考虑dstIn。 这对应于“Destination out Source”Porter-Duff运算符。 效果图如下:

图29 BlendMode.dstOut


BlendMode.dstOver

合成目标图像下的源图像。 这与srcOver相反。 这对应于“源上的目标”Porter-Duff运算符。 效果图如下:

图30 BlendMode.dstOver


BlendMode.exclusion

从两个图像的总和中减去两个图像的乘积的两倍。 合成黑色没有效果;合成白色会反转另一幅图像的颜色。 输出图像的不透明度的计算方法与srcOver相同。 效果图如下:

图31 BlendMode.exclusion

BlendMode.hardLight

将源图像和目标图像的组件调整为有利于源后,将它们相乘。 具体来说,如果源值较小,则将其与目标值相乘,而目标值较小,它将目标值的倒数乘以源值的倒数,然后反转结果。 反转组件意味着完全饱和的通道(不透明的白色)被视为值0.0,通常被视为0.0(黑色,透明)的值被视为1.0。 效果图如下:

图32 BlendMode.hardLight


BlendMode.hue

获取源图像的​​色调,以及目标图像的饱和度和亮度。 效果是使用源图像为目标图像着色。 输出图像的不透明度的计算方法与srcOver相同。 在源图像中完全透明的区域从目的地获取其色调。 效果图如下:

图33 BlendMode.hue


BlendMode.lighten

通过从每个颜色通道中选择最高值来合成源图像和目标图像。 输出图像的不透明度的计算方法与srcOver相同。 效果图如下:

图34 BlendMode.lighten


BlendMode.luminosity

获取源图像的​​亮度,以及目标图像的色调和饱和度。 输出图像的不透明度的计算方法与srcOver相同。 在源图像中完全透明的区域从目的地获取其亮度。 效果图如下:

图35 BlendMode.luminosity


BlendMode.modulate

将源图像和目标图像的颜色分量相乘。 这只能产生相同或较暗的颜色(乘以白色,1.0,结果不变;乘以黑色,0.0,结果为黑色)。 合成两个不透明图像时,这与在投影仪上重叠两个透明胶片具有相似的效果。 对于也乘以alpha通道的变体,请考虑乘法。 效果图如下:

图36 BlendMode.modulate


BlendMode.multiply

将源图像和目标图像的组件相乘,包括Alpha通道。 这只能产生相同或较暗的颜色(乘以白色,1.0,结果不变;乘以黑色,0.0,结果为黑色)。 由于Alpha通道也是相乘的,因此一个图像中的完全透明像素(不透明度为0.0)会在输出中产生完全透明的像素。这与dstIn类似,但颜色组合在一起。 对于将颜色相乘但不会乘以alpha通道的变体,请考虑调制。 效果图如下:

图37 BlendMode.multiply


BlendMode.overlay

在调整源图像和目标图像的组件以使其有利于目标之后,将其相乘。 具体来说,如果目标值较小,则将其与源值相乘,而源值较小,它将源值的倒数乘以目标值的倒数,然后反转结果。 反转组件意味着完全饱和的通道(不透明的白色)被视为值0.0,通常被视为0.0(黑色,透明)的值被视为1.0。 效果图如下:

图38 BlendMode.overlay


BlendMode.plus

对源图像和目标图像的组件求和。 其中一个图像的像素中的透明度降低了该图像对相应输出像素的贡献,就好像该图像中该像素的颜色较暗一样。 这对应于“Source plus Destination”Porter-Duff运算符。 效果图如下:

图39 BlendMode.plus


BlendMode.saturation

获取源图像的​​饱和度以及目标图像的色调和亮度。 输出图像的不透明度的计算方法与srcOver相同。 在源图像中完全透明的区域从目的地获取饱和度。 效果图如下:

图40 BlendMode.saturation


BlendMode.screen

将源图像和目标图像的分量的倒数相乘,并反转结果。 反转组件意味着完全饱和的通道(不透明的白色)被视为值0.0,通常被视为0.0(黑色,透明)的值被视为1.0。 这与调制混合模式基本相同,但是在乘法之前将颜色的值反转,并且在渲染之前将结果反转回来。 这只能产生相同或较浅的颜色(乘以黑色,1.0,结果不变;乘以白色,0.0,结果为白色)。同样,在alpha通道中,它只能产生更多不透明的颜色。 这与两台同时在同一屏幕上显示图像的投影机具有相似的效果。 效果图如下:

图41 BlendMode.screen


BlendMode.softLight

对于低于0.5的源值,使用colorDodge,对于高于0.5的源值,使用colorBurn。 这导致与覆盖相似但更柔和的效果。 效果图如下:

图42 BlendMode.softLight


BlendMode.srcATop

将源图像合成到目标图像上,但仅限于它与目标重叠的位置。 这对应于“Source atop Destination”Porter-Duff运算符。 这实际上是srcOver运算符,但输出的不透明度通道设置为目标图像的不透明度通道,而不是两个图像的不透明度通道的组合。 对于目标位于顶部而非源的变体,请参阅dstATop。 效果图如下:

图43 BlendMode.srcATop


BlendMode.srcIn

显示源图像,但仅显示两个图像重叠的位置。目标图像不会渲染,仅将其视为蒙版。将忽略目标的颜色通道,只有不透明度才有效。 要显示目标图像,请考虑dstIn。 要反转掩码的语义(仅显示目标不存在的源,而不是存在的位置),请考虑srcOut。 这对应于“目的地来源”Porter-Duff运算符。 效果图如下:

图44 BlendMode.srcIn


BlendMode.srcOut

显示源图像,但仅显示两个图像不重叠的位置。目标图像不会渲染,仅将其视为蒙版。将忽略目标的颜色通道,只有不透明度才有效。 要显示目标图像,请考虑dstOut。 要反转掩码的语义(仅显示目标所在的源,而不是缺少的位置),请考虑srcIn。 这对应于“Source out Destination”Porter-Duff运算符。 效果图如下:

图45 BlendMode.srcOut


BlendMode.srcOver

将源图像合成到目标图像上。 这是默认值。它代表了最直观的情况,其中形状被绘制在下面的内部,透明区域显示目标层。 这对应于“Source over Destination”Porter-Duff运算符,也称为Painter算法。 效果图如下:

图46 BlendMode.srcOver


BlendMode.xor

将按位xor运算符应用于源图像和目标图像。这会留下重叠的透明度。 这对应于“Source xor Destination”Porter-Duff运算符。 效果图如下:

图47 BlendMode.xor


七、fit Property

如何将图片放在盒子里。fit属性的值是枚举类型的BoxFit。

  • contain
  • cover
  • fill
  • fitHeight
  • fitWidth
  • none
  • scaleDown

代码如下:

//fit Property
class fit_Property_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: double.infinity,
        height: double.infinity,
        color: Colors.white,
        child: Container(
          decoration: BoxDecoration(
            image: DecorationImage(
                image: NetworkImage("http://jlouage.com/images/author.jpg"),
                fit: BoxFit.contain
            )
          ),
        ),
      ),
    );
  }
}

contain

在子类宽高比不变的前提下,子类尽可能的大,充满父类。一般情况下,宽度或者高度达到最大值时,就会停止缩放。

图48 contain

cover

图像应该尽可能小,但覆盖整个渲染框。所以小图片会被放大拉伸,直至覆盖整个渲染框。如果图片大于渲染框,图片会显示部分。

图49 cover

fill

图片会去适应当前渲染框,调整自身大小,充满整个屏幕。

图50 fill

fitHeight

高度要充满屏幕,无论宽度方向上,图片是否会溢出。

图51 fitHeight

fitWidth

宽度要充满屏幕,无论高度方向上,图片是否会溢出。

图52 fitWidth

none

图片按照原图展示,不进行任何缩放,超出父类的部分会被裁剪掉。保证图片居中显示。

图53 none

scaleDown

调整图片,让图片居中显示。如果需要缩小图片(同比例缩放),则与contain相同,否则与none相同。

图54 scaleDown

八、repeat Property

  • noRepeat
  • repeat
  • repeatX
  • repeatY

noRepeat

让Container未覆盖部分保持透明,只会出现一张图片。

代码如下:

//repeat Property
class repeat_Property_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: double.infinity,
        height: double.infinity,
        color: Colors.white,
        child: Container(
          decoration: BoxDecoration(
            image: DecorationImage(
                image: AssetImage("images/JL-Logo-150.png"),
                repeat: ImageRepeat.noRepeat,
                //repeat: ImageRepeat.repeat,
                //repeat: ImageRepeat.repeatX,
                //repeat: ImageRepeat.repeatY
            )
          ),
        ),
      ),
    );
  }
}

效果图如下:

图55 noRepeat


repeat

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

代码如下:

//repeat Property
class repeat_Property_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: double.infinity,
        height: double.infinity,
        color: Colors.white,
        child: Container(
          decoration: BoxDecoration(
            image: DecorationImage(
                image: AssetImage("images/JL-Logo-150.png"),
                //repeat: ImageRepeat.noRepeat,
                repeat: ImageRepeat.repeat,
                //repeat: ImageRepeat.repeatX,
                //repeat: ImageRepeat.repeatY
            )
          ),
        ),
      ),
    );
  }
}

效果图如下:

图56 repeat


repeatX

沿x方向重复图像,直到水平填充满容器。

代码如下:

//repeat Property
class repeat_Property_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: double.infinity,
        height: double.infinity,
        color: Colors.white,
        child: Container(
          decoration: BoxDecoration(
            image: DecorationImage(
                image: AssetImage("images/JL-Logo-150.png"),
                //repeat: ImageRepeat.noRepeat,
                //repeat: ImageRepeat.repeat,
                repeat: ImageRepeat.repeatX,
                //repeat: ImageRepeat.repeatY
            )
          ),
        ),
      ),
    );
  }
}

效果图如下:

图56 repeatX


repeatY

沿y方向重复图像,直到垂直填充满容器。

代码如下:

//repeat Property
class repeat_Property_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: double.infinity,
        height: double.infinity,
        color: Colors.white,
        child: Container(
          decoration: BoxDecoration(
            image: DecorationImage(
                image: AssetImage("images/JL-Logo-150.png"),
                //repeat: ImageRepeat.noRepeat,
                //repeat: ImageRepeat.repeat,
                //repeat: ImageRepeat.repeatX,
                repeat: ImageRepeat.repeatY
            )
          ),
        ),
      ),
    );
  }
}

效果图如下:

图57 repeatY


九、matchTextDirection Property

决定图片是否根据TextDirection设置进行变换。它的值是truefalse

这个属性需要配合Directionality使用。

如果当前是TextDirection.ltr,matchTextDirection设置位true,那么图片将从原点的左上方开始绘制(图片正常绘制的方向)。 如果当前是TextDirection.rtl,matchTextDirection设置位true,那么图片将从原点的右上方开始绘制,图片进行反转。 代码如下:

//matchTextDirection Property
//配合Directionality
class matchTextDirection_Property_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: double.infinity,
        height: double.infinity,
        color: Colors.white,
        child: Directionality(
            textDirection: TextDirection.rtl,
            child: Container(
              decoration: BoxDecoration(
                image: DecorationImage(
                    image: AssetImage("images/icon1.png"),
                  matchTextDirection: true,
                )
              ),
            )
        ),
      ),
    );
  }
}

效果图如下:

图58 matchTextDirection


十、Border Property

在背景color、gradient或image上面绘制边框。

Border Property 可以取值为 Border Class、Border.all、BorderDirectional Class。

其中Border和BorderDirectional可以用于设置特定边界边框。 Border.all用于设置所有边框。

这里先介绍Border.all属性,它有3个参数:

  • color:设置颜色
  • width:边框宽度
  • style:边界风格,这里主要有2个风格:BorderStyle.solid 和BorderStyle.none。 代码如下:
//Border Property
class Border_Property_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: 300.0,
        height: 300.0,
        color: Colors.white,
        child: Container(
          decoration: BoxDecoration(
            border: Border.all(
              color: Colors.green,
              width: 5.0,
              style: BorderStyle.solid
            ),
            image: DecorationImage(
               image:AssetImage("images/JL-Logo-150.png")
             )    
          ),
        ),
      ),
    );
  }
}

效果图如下:

图59 Border Property


现在我们使用Border Class代替Border.all。Border Class总共有4个参数top,bottom,left, right。每个参数的值是BorderSide Class。 代码如下:

//Border Property
//Border
class Border_Border_Property_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: 300.0,
        height: 300.0,
        color: Colors.white,
        child: Container(
          decoration: BoxDecoration(
            border: Border(
              top: BorderSide(
                color: Colors.green,
                width: 5.0,
                style: BorderStyle.solid
              )
            ),
            image: DecorationImage(
                image:AssetImage("images/JL-Logo-150.png")
            )
          ),
        ),
      ),
    );
  }
}

效果图如下:

图60 Border


现在使用一下BorderDirectional。 BorderDirectional和Border Class类似,有4个参数,但是没有left和right,取而代之的是start和end。 代码如下:

//Border Property
//BorderDirectional
class Border_BorderDirectional_Property_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: 300,
        height: 300,
        color: Colors.white,
        child: Container(
          decoration: BoxDecoration(
            border: BorderDirectional(
              top: BorderSide(
                color: Colors.green,
                width: 5.0,
                style: BorderStyle.solid
              ),
              start: BorderSide(
                color: Colors.green,
                width: 5.0,
                style: BorderStyle.solid
              )
            ),
            image: DecorationImage(
              image:AssetImage("images/JL-Logo-150.png")
            )    
          ),
        ),
      ),
    );
  }
}

效果图如下:

图61 BorderDirectional


十一、borderRadius Property

如果你想容器四周出现圆角,你可以使用borderRadius。

注意: borderRadius只适用于矩形形状的盒子。

对应的取值是BorderRadius.all、BorderRadius.only、BorderRadius.circular、BorderRadius.horizontal、BorderRadius.vertical。

同样你可以使用BorderRadiusDirectional代替BorderRadius,但是参数里面会将left和right替换为start和end。

BorderRadius.all

代码如下:

//borderRadius Property
//BorderRadius.all
class borderRadius_Property_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: 300.0,
        height: 300.0,
        color: Colors.white,
        child: Container(
          decoration: BoxDecoration(
            border: Border.all(
              color: Colors.green,
              width: 5.0,
              style: BorderStyle.solid
            ),
            borderRadius:BorderRadius.all(Radius.circular(20.0)),
            image: DecorationImage(
                image:AssetImage("images/JL-Logo-150.png")
            )
          ),
        ),
      ),
    );
  }
}

效果图如下:

图62 Border.all


现在来使用一下BorderRadius.circular 代码如下;

//borderRadius Property
//BorderRadius.circular
class borderRadius_Property_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: 300.0,
        height: 300.0,
        color: Colors.white,
        child: Container(
          decoration: BoxDecoration(
            border: Border.all(
              color: Colors.green,
              width: 5.0,
              style: BorderStyle.solid
            ),
            //borderRadius:BorderRadius.all(Radius.circular(20.0)),
            borderRadius:BorderRadius.circular(20.0),
            image: DecorationImage(
                image:AssetImage("images/JL-Logo-150.png")
            )
          ),
        ),
      ),
    );
  }
}

效果图如下:

图63 BorderRadius.circular


由上面图可以知道,BorderRadius.circular和BorderRadius.all效果一致,不过BorderRadius.circular可以直接输入浮点型数据。

BorderRadius.horizontal

BorderRadius.horizontal会创建一个水平对称的边框半径,其中矩形框的左右两侧具有相同的半径。 代码如下:

//borderRadius Property
//BorderRadius.horizontal
class BorderRadius_horizontal_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: 300.0,
        height: 300.0,
        color: Colors.white,
        child: Container(
          decoration: BoxDecoration(
            border: Border.all(
              color: Colors.green,
              width: 5.0,
              style: BorderStyle.solid
            ),
            borderRadius: BorderRadius.horizontal(
              left: Radius.circular(20.0),
              //right: new Radius.circular(20.0),
            ),
            image: DecorationImage(
                image: AssetImage("images/JL-Logo-150.png")
            )
          ),
        ),
      ),
    );
  }
}

效果图如下:

图64 BorderRadius.horizontal


BorderRadius.vertical

BorderRadius.vertical会创建一个垂直对称的边框半径,其中矩形的上下两侧具有相同的半径 代码如下:

//borderRadius Property
//BorderRadius.vertical
class BorderRadius_vertical_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: 300.0,
        height: 300.0,
        color: Colors.white,
        child: Container(
          decoration: BoxDecoration(
            border: Border.all(
              color: Colors.green,
              width: 5.0,
              style: BorderStyle.solid
            ),
            borderRadius: BorderRadius.vertical(
              top: Radius.circular(20.0),
              //bottom: new Radius.circular(20.0),
            ),
            image: DecorationImage(
                image: AssetImage("images/JL-Logo-150.png"),
            )  
          ),
        ),
      ),
    );
  }
}

效果图如下:

图65 BorderRadius.vertical


BorderRadius.only

BorderRadius.only仅创建包含非零值的边框半径。其它角则是直角。 代码如下:

//borderRadius Property
//BorderRadius.only
class BorderRadius_only_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: 300.0,
        height: 300.0,
        color: Colors.white,
        child: Container(
          decoration: BoxDecoration(
            border: Border.all(
              color: Colors.green,
              width: 5.0,
              style: BorderStyle.solid
            ),
            borderRadius: BorderRadius.only(
              topLeft: Radius.circular(20.0),
              //topRight: Radius.circular(20.0),
              bottomRight: Radius.circular(20.0),
              //bottomLeft: Radius.circular(20.0),
            ),
            image: DecorationImage(
                image:AssetImage("images/JL-Logo-150.png")
            )  
          ),
        ),
      ),
    );
  }
}

效果图如下:

图66 BorderRadius.only


另外,你也可以使用Radius.elliptical代替Radius.circular。Radius.elliptical有2个参数(x,y)。 代码如下:

//borderRadius Property
//Radius.elliptical
class Radius_elliptical_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
        child: Container(
          width: 300.0,
          height: 300.0,
          color: Colors.white,
          child: Container(
            decoration: BoxDecoration(
              border: Border.all(
                color: Colors.green,
                width: 5.0,
                style: BorderStyle.solid
              ),
              borderRadius: BorderRadius.only(
                 topLeft: Radius.elliptical(40.0, 10.0),
                 //topRight: Radius.circular(20.0),
                 bottomRight: Radius.circular(20.0),
                 //bottomLeft: Radius.circular(20.0),
              ),
              image: DecorationImage(
                  image:AssetImage("images/JL-Logo-150.png")
              )
            ),
          ),
        ),
    );
  }
}

效果图如下:

图67 Radius.elliptical


十二、boxShadow Property

这个用于设置盒子的阴影,这个阴影和盒子的形状保持一致。 boxShadow的值是一个包含BoxShadow的列表。你可以在列表中使用multiple BoxShadow

BoxShadow有下面4个参数

  • color:阴影的颜色
  • offset:阴影相对于盒子的偏移量
  • blurRadius:高斯的标准偏差与盒子的形状卷积。
  • spreadRadius:在应用模糊之前,框应该膨胀的量。

第一个例子我们使用color和offset。 offset参数的值是一个Offset类,并且有2个浮点型参数x和y。 代码如下:

//boxShadow Property
//color和offset
class boxShadow_colorAndoffset_Property_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: 200.0,
        height: 200.0,
        color: Colors.white,
        child: Container(
          decoration: BoxDecoration(
            color: Colors.white,
            border: Border.all(
              color: Colors.green,
              width: 5.0,
              style: BorderStyle.solid
            ),
            borderRadius: BorderRadius.only(
              topLeft: Radius.elliptical(40.0, 10.0),
              bottomLeft: Radius.circular(20.0),
            ),
            boxShadow: [
              BoxShadow(
                color: Colors.red,
                offset: Offset(20.0, 10.0)
              )
            ],
            image: DecorationImage(
                image:AssetImage("images/JL-Logo-150.png")
            )
          ),
        ),
      ),
    );
  }
}

效果图如下:

图68 boxShadow

上图我们将阴影沿X轴平移20,沿Y轴平移10。这个阴影是实体的。

这里我们添加blurRadius属性,让它成为一个真正的阴影。 代码如下:

//boxShadow Property
//blurRadius
class boxShadow_blurRadius_Property_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: 300.0,
        height: 300.0,
        color: Colors.white,
        child: Container(
          decoration: BoxDecoration(
            color: Colors.white,
            border: Border.all(
              color: Colors.green,
              width: 5.0,
              style: BorderStyle.solid
            ),
            borderRadius: BorderRadius.only(
              topLeft: Radius.elliptical(40.0, 10.0),
              bottomLeft: Radius.circular(20.0),
            ),
            boxShadow: [
              BoxShadow(
                color: Colors.red,
                offset: Offset(20.0, 10.0),
                blurRadius: 20.0,
              )
            ],
            image: DecorationImage(
                image: AssetImage("images/JL-Logo-150.png")
            )
          ),
        ),
      ),
    );
  }
}

效果图如下:

图69 blurRadius

现在将阴影进一步扩散。我们将使用spreadRadius。 代码如下:

//boxShadow Property
//spreadRadius
class boxShadow_spreadRadius_Property_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: 300.0,
        height: 300.0,
        color: Colors.white,
        child: Container(
          decoration: BoxDecoration(
            color: Colors.white,
            border: Border.all(
              color: Colors.green,
              width: 5.0,
              style: BorderStyle.solid
            ),
            borderRadius: BorderRadius.only(
              topLeft: Radius.elliptical(40.0, 10.0),
              bottomLeft: Radius.circular(20.0),
            ),
            boxShadow: [
              BoxShadow(
                color: Colors.red,
                offset: Offset(20.0, 10.0),
                blurRadius: 20.0,
                spreadRadius: 40.0,
              )
            ],
            image: DecorationImage(
                image:AssetImage("images/JL-Logo-150.png")
            )
          ),
        ),
      ),
    );
  }
}

效果图如下:

图70 spreadRadius

现在我们使用多种BoxShadow。 代码如下:

//boxShadow Property
//multiple BoxShadow
class boxShadow_multipleAndBoxShadow_Property_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: 300.0,
        height: 300.0,
        color: Colors.white,
        child: Container(
          decoration: BoxDecoration(
              color: Colors.white,
              border: Border.all(
                  color: Colors.green,
                  width: 5.0,
                  style: BorderStyle.solid
              ),
              borderRadius: BorderRadius.only(
                topLeft: Radius.elliptical(40.0, 10.0),
                bottomLeft: Radius.circular(20.0),
              ),
              boxShadow: [
                BoxShadow(
                  color: Colors.red,
                  offset: Offset(20.0, 10.0),
                  blurRadius: 20.0,
                  spreadRadius: 40.0,
                ),
                BoxShadow(
                  color: Colors.yellow,
                  offset: Offset(20.0, 10.0),
                  blurRadius: 20.0,
                  spreadRadius: 20.0,
                ),
                BoxShadow(
                  color: Colors.green,
                  offset: Offset(10.0, 5.0),
                  blurRadius: 20.0,
                  spreadRadius: 5.0,
                )
              ],
              image: DecorationImage(
                  image:AssetImage("images/JL-Logo-150.png")
              )
          ),
        ),
      ),
    );
  }
}

效果图如下:

图71 multiple BoxShadow

十三、shape Property

用于设置图片形状。 shape属性值是枚举类型的BoxShape。

  • BoxShape.rectangle
  • BoxShape.circle **注意:**如果值是BoxShape.circle,那么borderRadius将无效。 代码如下:
//shape Property
class shape_Property_Widget extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Container(
        width: 300.0,
        height: 300.0,
        child: Container(
          decoration: BoxDecoration(
            color: Colors.white,
            border: Border.all(
              color: Colors.green,
              width: 5.0,
              style: BorderStyle.solid
            ),
            boxShadow: [
              BoxShadow(
                color: Colors.red,
                offset: Offset(20.0, 10.0),
                blurRadius: 20.0,
                spreadRadius: 40.0
              )
            ],
            shape: BoxShape.circle,
            image: DecorationImage(
                image: AssetImage("images/JL-Logo-150.png")
            )
          ),
        ),
      ),
    );
  }
}

效果图如下:

图72 shape

十四、Padding Property

请查看Flutter之Container用法详解

参考文章

Flutter — BoxDecoration Cheat Sheet