Flutter之BoxDecoration用法詳解

小川同志發表於2019-02-15

前言

前面我們介紹了Container用法:Flutter之Container用法詳解
這裡要詳細講解一下BoxDecoration這個屬性:

  • 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

相關文章