Widget
和佈局類Widget
都做用於其子Widget
,不一樣的是:
Widget
通常都須要接收一個widget
數組(children
),他們直接或間接繼承自(或包含)MultiChildRenderObjectWidget
Widget
通常只須要接受一個子Widget
(child
),他們直接或間接繼承自(或包含)SingleChildRenderObjectWidget
Widget
是按照必定的排列方式來對其子Widget
進行排列Widget
通常只是包裝其子Widget
,對其添加一些修飾(補白或背景色等)、變換(旋轉或剪裁等)、或限制(大小等)。Flutter
官方並無對Widget
進行官方分類,咱們對其分類主要是爲了方便討論和對Widget
功能的區分記憶Widget
主要分爲如下幾種
Padding
ConstrainedBox
、SizeBox
DecoratedBox
Transform
Container
Scaffold
、TabBar
、AppBar
等Padding
能夠給其子元素設置內邊距git
class Padding extends SingleChildRenderObjectWidget {
const Padding({
Key key,
// 內邊距
@required this.padding,
Widget child,
})
final EdgeInsetsGeometry padding;
}
複製代碼
EdgeInsetsGeometry
是一個抽象類,通常狀況都使用EdgeInsets
,它是EdgeInsetsGeometry
的一個子類, 下面是的定義的一些方法github
class EdgeInsets extends EdgeInsetsGeometry {
// 根據上下左右分別設置邊距
const EdgeInsets.fromLTRB(this.left, this.top, this.right, this.bottom);
// 統一設置四周邊距
const EdgeInsets.all(double value)
// 只設置其中某幾個邊距
const EdgeInsets.only({
// 下面的都是默認值
this.left = 0.0,
this.top = 0.0,
this.right = 0.0,
this.bottom = 0.0
});
// 根據水平和垂直方向設置, 上下間距同樣, 左右間距同樣
const EdgeInsets.symmetric({ double vertical = 0.0,
double horizontal = 0.0 })
// 靜態變量, 上下左右, 都是0
static const EdgeInsets zero = EdgeInsets.only();
}
複製代碼
示例數組
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(20),
child: Icon(Icons.phone, color: Colors.cyan,),
);
}
}
複製代碼
ConstrainedBox
和SizedBox
都是經過RenderConstrainedBox
來渲染的SizedBox
只是ConstrainedBox
一個定製ConstrainedBox
主要用於對子widget
添加額外的約束class ConstrainedBox extends SingleChildRenderObjectWidget {
ConstrainedBox({
Key key,
@required this.constraints,
Widget child
})
/// 給子widget添加約束
final BoxConstraints constraints;
複製代碼
BoxConstraints
設置Widget
的約束, 內部設置了四個屬性: 最大/小寬度和最大小高度, 下面是其相關構造函數和實例函數bash
class BoxConstraints extends Constraints {
/// 構造函數
const BoxConstraints({
// 最小寬度
this.minWidth = 0.0,
// 最大寬度
this.maxWidth = double.infinity,
// 最小高度
this.minHeight = 0.0,
// 最大高度
this.maxHeight = double.infinity
});
/// 根據指定的Size設置約束
BoxConstraints.tight(Size size)
: minWidth = size.width,
maxWidth = size.width,
minHeight = size.height,
maxHeight = size.height;
// 根據指定的寬高設置, 參數可爲空
const BoxConstraints.tightFor({
double width,
double height
}): minWidth = width != null ? width : 0.0,
maxWidth = width != null ? width : double.infinity,
minHeight = height != null ? height : 0.0,
maxHeight = height != null ? height : double.infinity;
// 默認寬高都是最大值, 參數可爲空
const BoxConstraints.tightForFinite({
double width = double.infinity,
double height = double.infinity
}): minWidth = width != double.infinity ? width : 0.0,
maxWidth = width != double.infinity ? width : double.infinity,
minHeight = height != double.infinity ? height : 0.0,
maxHeight = height != double.infinity ? height : double.infinity;
// 根據Size參數, 設置其最大值, 最小值爲0
BoxConstraints.loose(Size size)
: minWidth = 0.0,
maxWidth = size.width,
minHeight = 0.0,
maxHeight = size.height;
// 根據寬高設置, 若是參數爲空則默認爲最大值
const BoxConstraints.expand({
double width,
double height
}): minWidth = width != null ? width : double.infinity,
maxWidth = width != null ? width : double.infinity,
minHeight = height != null ? height : double.infinity,
maxHeight = height != null ? height : double.infinity;
}
複製代碼
使用實例微信
class ConstrainedBoxView extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return ConstrainedBox(
constraints: BoxConstraints(
minWidth: double.infinity, // 寬度設置最大
minHeight: 50, // 高度最小值設置50
),
child: Container(
height: 10, // 設置高度爲10
child: DecoratedBox(decoration: BoxDecoration(color: Colors.orange)),
),
);
}
}
複製代碼
Container
的高度設置爲10像素,可是最終倒是50像素,這正是ConstrainedBox
的最小高度限制生效了Container
的高度設置爲80像素,那麼最終紅色區域的高度也會是80像素,由於在此示例中,ConstrainedBox
只限制了最小高度,並未限制最大高度SizedBox
用於給子widget
指定固定的寬高markdown
// SizedBox的幾種構造函數
class SizedBox extends SingleChildRenderObjectWidget {
/// 設置固定的高度
const SizedBox({ Key key, this.width, this.height, Widget child })
: super(key: key, child: child);
/// 建立一個最大寬高的box
const SizedBox.expand({ Key key, Widget child })
: width = double.infinity,
height = double.infinity,
super(key: key, child: child);
/// 建立一個最小寬高(都是0)的box
const SizedBox.shrink({ Key key, Widget child })
: width = 0.0,
height = 0.0,
super(key: key, child: child);
/// 建立一個指定size 的box
SizedBox.fromSize({ Key key, Widget child, Size size })
: width = size?.width,
height = size?.height,
super(key: key, child: child);
}
複製代碼
這裏咱們建立一個指定寬高的Widget
less
class SizedBoxView extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return SizedBox(
width: 80,
height: 80,
child: Container(
child: DecoratedBox(decoration: BoxDecoration(color: Colors.orange)),
),
);
}
}
// 實際上SizedBox和只是ConstrainedBox一個定製, 上面的代碼等價於
ConstrainedBox(
constraints: BoxConstraints.tightFor(width: 80.0,height: 80.0),
child: Container(
child: DecoratedBox(decoration: BoxDecoration(color: Colors.orange)),
),
)
複製代碼
而實際上ConstrainedBox
和SizedBox
都是經過RenderConstrainedBox
來渲染的,咱們能夠看到ConstrainedBox
和SizedBox
的createRenderObject()
方法都返回的是一個RenderConstrainedBox
對象ide
// SizedBox
class SizedBox extends SingleChildRenderObjectWidget {
RenderConstrainedBox createRenderObject(BuildContext context) {
return RenderConstrainedBox(
additionalConstraints: _additionalConstraints,
);
}
BoxConstraints get _additionalConstraints {
return BoxConstraints.tightFor(width: width, height: height);
}
}
// ConstrainedBox
class ConstrainedBox extends SingleChildRenderObjectWidget {
RenderConstrainedBox createRenderObject(BuildContext context) {
return RenderConstrainedBox(additionalConstraints: constraints);
}
final BoxConstraints constraints;
}
複製代碼
多重限制問題函數
widget
有多個父ConstrainedBox
限制minWidth
和minHeight
來講,是取父子中相應數值較大的。只有這樣才能保證父限制與子限制不衝突maxWidth
和maxHeight
來講, 無效, 最終寬高都是0const UnconstrainedBox({
Key key,
Widget child,
// TextDirection, 表示水平方向子widget的佈局順序
this.textDirection,
// 子Widget在主軸上的對其方式
this.alignment = Alignment.center,
// 設置約束的軸, 水平or垂直, Axis.horizontal
this.constrainedAxis,
})
複製代碼
UnconstrainedBox
不會對子Widget
產生任何限制,它容許其子Widget
按照其自己大小繪製widget
,但在"去除"多重限制的時候也許會有幫助ConstrainedBox(
constraints: BoxConstraints(
minWidth: 60,
minHeight: 100,
),
child: UnconstrainedBox( // 「去除」父級限制
textDirection: TextDirection.ltr,
alignment: Alignment.center,
constrainedAxis: Axis.horizontal,
child: ConstrainedBox(
constraints: BoxConstraints(
minWidth: 90,
minHeight: 20,
),
child: DecoratedBox(decoration: BoxDecoration(color: Colors.red)),
),
)
);
複製代碼
UnconstrainedBox
,那麼根據上面所述的多重限制規則,那麼最終將顯示一個90×100的紅色框UnconstrainedBox
「去除」了父ConstrainedBox
的限制,則最終會按照子ConstrainedBox
的限制來繪製紅色框,即90×20:UnconstrainedBox
對父限制的「去除」並不是是真正的去除,上面例子中雖然紅色區域大小是90×20,但上方仍然有80的空白空間。minHeight
(100.0)仍然是生效的,只不過它不影響最終子元素的大小,但仍然仍是佔有相應的空間,能夠認爲此時的父ConstrainedBox
是做用於子ConstrainedBox
上,而紅色框只受子ConstrainedBox
限制,這一點請讀者務必注意BoxConstraints
的限制widget
時,若是對子widget
指定限制時必定要注意,由於一旦指定限制條件,子widget
若是要進行相關自定義大小時將可能很是困難,由於子widget
在不更改父widget
的代碼的狀況下沒法完全去除其限制條件DecoratedBox
能夠在其子widget
繪製前(或後)繪製一個裝飾Decoration
(如背景、邊框、漸變等), 構造函數以下佈局
const DecoratedBox({
Key key,
@required this.decoration,
this.position = DecorationPosition.background,
Widget child
})
複製代碼
decoration
: 表明將要繪製的裝飾,它類型爲Decoration
是一個抽象類,它定義了一個接口 createBoxPainter()
,子類的主要職責是須要經過實現它來建立一個裝飾器, 因此後面咱們將使用BoxDecoration
來實現該屬性position
:此屬性決定在哪裏繪製Decoration
,它接收DecorationPosition
的枚舉類型,該枚舉類兩個值:
background
:在子widget
以後繪製,即背景裝飾(是默認值)foreground
:在子widget
之上繪製,即前景BoxDecoration
是一個Decoration
的子類, 一般咱們都是使用它來實現上面的相似decoration
的相關屬性
const BoxDecoration({
// 背景顏色
this.color,
// 背景圖片, DecorationImage
this.image,
// 邊框
this.border,
// 圓角
this.borderRadius,
// 陰影
this.boxShadow,
// 漸變色
this.gradient,
// 背景顏色和背景圖片的混合渲染模式`BlendMode`, 下面會介紹該枚舉值
this.backgroundBlendMode,
// 形狀
this.shape = BoxShape.rectangle,
})
複製代碼
設置背景圖片DecorationImage
const DecorationImage({
// ImageProvider類型
@required this.image,
this.colorFilter,
this.fit,
this.alignment = Alignment.center,
this.centerSlice,
this.repeat = ImageRepeat.noRepeat,
this.matchTextDirection = false,
})
複製代碼
ImageProvider
類型的ImageProvider
是一個抽象類, 須要使用其子類實現
NetworkImage
FileImage
MemoryImage
ColorFilter
類ColorFilter
的構造方法中有兩個屬性, 分別設置顏色圖像和圖片圖像, 後面也將使用這兩個名詞解釋各個枚舉值// 兩個屬性, 分別設置顏色圖像和圖片圖像
const ColorFilter.mode(Color color, BlendMode blendMode)
複製代碼
BlendMode
有如下枚舉值, 帶有src
表示圖片圖像不顯示, dst
表示顏色圖像不顯示
blendMode |
枚舉值意義 |
---|---|
clear |
顏色圖像和圖片圖像都不顯示 |
src |
顯示顏色圖像不顯示圖片圖像 |
dst |
顯示圖片圖像不顯示顏色圖像 |
srcOver |
顏色圖像在圖片圖像的上面 |
dstOver |
顏色圖像在圖片圖像的下面 |
srcIn |
顯示圖片圖像, 但只顯示和顏色圖像重合的部分(二者的交集) |
dstIn |
顯示顏色圖像, 但只顯示和圖片圖像重合的部分(二者的交集) |
srcOut |
顯示圖片圖像, 但只顯示和顏色圖像不重合的部分(二者的差集) |
dstOut |
顯示顏色圖像, 但只顯示和圖片圖像不重合的部分(二者的差集), 通常都是空了 |
srcATop |
將圖片圖像合成到顏色圖像上面, 只合成交集的部分 |
dstATop |
將顏色圖像合成到圖片圖像上面, 只合成交集的部分 |
xor |
圖片圖像和顏色圖像合成的結果 |
plus |
圖片和顏色的合成, 可是會受透明度的影響 |
modulate |
將圖片圖像和顏色圖像的顏色份量相乘。這隻能產生相同或較暗的顏色(乘以白色,1.0,結果不變;乘以黑色,0.0,結果爲黑色 |
screen |
將圖片圖像和顏色圖像的顏色份量的倒數相乘, 並反轉結果 |
overlay |
在調整圖片圖像和顏色圖像的組件以使其有利於目標以後,將其相乘 |
darken |
經過從每一個顏色通道中選擇最低值來合成圖片圖像和顏色圖像 |
lighten |
經過從每一個顏色通道中選擇最高值來合成圖片圖像和顏色圖像 |
除此以外還有好幾個枚舉值, 可是我確實不知道該怎麼解釋了, 上面的解釋好像也不是很清晰, 模模糊糊, 仍是建議你們自測看效果圖吧, 或者看看官方文檔, 也有效果圖, 其實不少枚舉值仍是用不到的, 若是有比較好的解釋的話, 歡迎你們多多提出建議.........大寫的尷尬
設置邊框的樣式,BoxBorder
是一個抽象類, 有如下兩個類共三種實現方式
// Border的兩種實現方式
class Border extends BoxBorder {
const Border({
this.top = BorderSide.none,
this.right = BorderSide.none,
this.bottom = BorderSide.none,
this.left = BorderSide.none,
})
factory Border.all({
Color color = const Color(0xFF000000),
double width = 1.0,
BorderStyle style = BorderStyle.solid,
})
}
// 下面是BorderSide的構造函數, 以前的文字中都介紹過, 這裏就不在說起了
class BorderSide {
const BorderSide({
this.color = const Color(0xFF000000),
this.width = 1.0,
this.style = BorderStyle.solid,
})
}
// BorderDirectional的構造函數
class BorderDirectional extends BoxBorder {
const BorderDirectional({
this.top = BorderSide.none,
this.start = BorderSide.none,
this.end = BorderSide.none,
this.bottom = BorderSide.none,
})
}
複製代碼
設置盒子的陰影, 這個陰影和盒子的形狀保持一致, 接受的值是一個存儲BoxShadow
的列表, 下面下看一下BoxShadow
的構造函數
const BoxShadow({
// 顏色
Color color = const Color(0xFF000000),
// 陰影相對於盒子的偏移量
Offset offset = Offset.zero,
// 陰影的模糊程度, 值越大陰影越模糊
double blurRadius = 0.0,
// 陰影向相反方向增長的像素值
this.spreadRadius = 0.0
})
// 演示示例, 四個邊都添加陰影
[
BoxShadow(color: Colors.grey, offset: Offset(-5, -5), blurRadius: 10, spreadRadius: 0),
BoxShadow(color: Colors.red, offset: Offset(5, 5), blurRadius: 10, spreadRadius: 0),
],
複製代碼
設置背景顏色爲漸變色, Gradient
又是一個抽象類, 以下一共有三個子類
LinearGradient
RadialGradient
SweepGradient
// 線性漸變
const LinearGradient({
// 起始點
this.begin = Alignment.centerLeft,
// 終點
this.end = Alignment.centerRight,
// 色值數組
@required List<Color> colors,
// 值列表,裝有0.0到1.0的數值
List<double> stops,
// 漸變平鋪模式,指定在開始和結束之外的區域平鋪模式
this.tileMode = TileMode.clamp,
})
// 圓形漸變,
const RadialGradient({
// 漸變的中心)
this.center = Alignment.center,
// 漸變的半徑,浮點型,具體數值須要乘以盒子的寬度
this.radius = 0.5,
@required List<Color> colors,
List<double> stops,
this.tileMode = TileMode.clamp,
this.focal,
this.focalRadius = 0.0
})
const SweepGradient({
// 位置的中心點
this.center = Alignment.center,
// 起始點的角度
this.startAngle = 0.0,
// 終點的角度
this.endAngle = math.pi * 2,
@required List<Color> colors,
List<double> stops,
this.tileMode = TileMode.clamp,
})
複製代碼
三種漸變色效果以下所示
LinearGradient
線性漸變色下, 漸變模式TileMode
各枚舉值對應的效果以下
設置背景的形狀, 針對背景色, 背景圖片和漸變色, BoxShape
類型是個枚舉值
enum BoxShape {
// 保持不變
rectangle,
// 剪切成圓形, 和borderRadius屬性衝突
circle,
}
複製代碼
Transform
能夠在其子Widget
繪製時對其進行一個矩陣變換, 能夠對child
作平移、旋轉、縮放等操做Matrix4
是一個4D矩陣,經過它能夠實現各類矩陣操做先來看下Transform
的一些構造函數吧
class Transform extends SingleChildRenderObjectWidget {
// 建立一個矩陣變換Widget
const Transform({
Key key,
// 矩陣執行的變換操做, 接受一個Matrix4對象
@required this.transform,
// 旋轉點,相對於左上角頂點的偏移。默認旋轉點事左上角頂點,
// 接受一個Offset對象
this.origin,
// 對其方式
this.alignment,
// 點擊區域是否也作相應的改變
this.transformHitTests = true,
Widget child,
})
// 建立一個旋轉變換矩陣
Transform.rotate({
Key key,
// 設置旋轉角度
@required double angle,
this.origin,
this.alignment = Alignment.center,
this.transformHitTests = true,
Widget child,
})
// 建立一個平移矩陣
Transform.translate({
Key key,
@required Offset offset,
this.transformHitTests = true,
Widget child,
})
// 建立一個縮放矩陣
Transform.scale({
Key key,
// 設置縮放比例, 0-1的數值
@required double scale,
this.origin,
this.alignment = Alignment.center,
this.transformHitTests = true,
Widget child,
})
}
複製代碼
下面是每一種變換形式的具體示例
Transform.rotate
能夠對子widget
進行旋轉變換, 以下代碼
Container(
color: Colors.black,
child: Transform.rotate(
// 這裏☞旋轉的角度, math.pi是指180度
angle: -math.pi / 4,
child: Container(
padding: const EdgeInsets.all(8.0),
color: const Color(0xFFE8581C),
child: const Text('https://titanjun.top'),
),
)
)
複製代碼
Transform.translate
接收一個offset
參數,能夠在繪製時沿x、y軸對子widget
平移指定的距離
Container(
color: Colors.black,
child: Transform.translate(
// 默認原點爲左上角,右移5像素,向下平移15像素
offset: const Offset(5.0, 15.0),
child: Container(
padding: const EdgeInsets.all(8.0),
color: const Color(0xFF7F7F7F),
child: const Text('Quarter'),
),
)
)
複製代碼
Transform.scale
能夠對子Widget
進行縮小或放大
Container(
color: Colors.black,
child: Transform.scale(
origin: Offset(5, 5),
// 縮小爲原來的0.5倍
scale: 0.5,
child: Container(
padding: const EdgeInsets.all(8.0),
color: const Color(0xFFE8581C),
child: const Text('Bad Ideas'),
),
)
)
複製代碼
Transform
的變換是應用在繪製階段,而並非應用在佈局(layout
)階段Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
DecoratedBox(
decoration:BoxDecoration(color: Colors.red),
child: Transform.scale(scale: 1.5,
child: Text("Hello world")
)
),
Text("你好", style: TextStyle(color: Colors.green, fontSize: 18.0),)
],
)
複製代碼
Text
應用變換(放大)後,其在繪製時會放大,但其佔用的空間依然爲紅色部分,因此第二個text
會緊挨着紅色部分,最終就會出現文字有重合部分。layout
的開銷,因此性能會比較好Flow widget
,它內部就是用矩陣變換來更新UI,除此以外,Flutter
的動畫widget
中也大量使用了Transform
以提升性能RotatedBox
和Transform.rotate
功能類似,它們均可以對子widget
進行旋轉變換,可是有一點不一樣:RotatedBox
的變換是在layout
階段,會影響在子widget
的位置和大小Transform.rotate
時的示例改一下Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
DecoratedBox(
decoration: BoxDecoration(color: Colors.red),
//將Transform.rotate換成RotatedBox
child: RotatedBox(
// int類型
quarterTurns: 1, //旋轉90度(1/4圈)
child: Text("Hello world"),
),
),
Text("你好", style: TextStyle(color: Colors.green, fontSize: 18.0),)
],
),
複製代碼
因爲
RotatedBox
是做用於layout
階段,因此widget
會旋轉90度(而不僅是繪製的內容),decoration
會做用到widget
所佔用的實際空間上,因此就是上圖的效果。讀者能夠和前面Transform.rotate
示例對比理解
一個4D變換矩陣, Transform
使用Matrix4
使其子Widget
進行矩陣變換, 下面是其相關構造函數
// 4 x 4矩陣
factory Matrix4(double arg0, double arg1, double arg2, double arg3, double arg4, double arg5, double arg6, double arg7, double arg8, double arg9, double arg10, double arg11, double arg12, double arg13, double arg14, double arg15)
// 設置一個新的矩陣
factory Matrix4.columns(Vector4 arg0, Vector4 arg1, Vector4 arg2, Vector4 arg3)
// 複合平移、旋轉、縮放,造成新的轉換矩陣
factory Matrix4.compose(Vector3 translation, Quaternion rotation, Vector3 scale)
// 複製一個4*4的張量(矩陣)
factory Matrix4.copy(Matrix4 other)
// 縮放矩陣, Vector3(double x, double y, double z)
factory Matrix4.diagonal3(Vector3 scale)
// 縮放矩陣, 只是參數不一樣而已
factory Matrix4.diagonal3Values(double x, double y, double z)
Matrix4.fromBuffer(ByteBuffer buffer, int offset)
// 使用給定的Float64List構造Matrix4
Matrix4.fromFloat64List(Float64List _m4storage)
// 將一個16位的一維數組轉換成4*4的矩陣
factory Matrix4.fromList(List<double> values)
// 恢復初始狀態,也就是4*4的單位矩陣
factory Matrix4.identity()
// 取相反的矩陣,就是反着來
factory Matrix4.inverted(Matrix4 other)
// 兩個4維向量的乘積合併
factory Matrix4.outer(Vector4 u, Vector4 v)
// 圍繞X軸旋轉
factory Matrix4.rotationX(double radians)
// 圍繞Y軸旋轉
factory Matrix4.rotationY(double radians)
// 圍繞Z軸旋轉
factory Matrix4.rotationZ(double radians)
// 扭曲變換
factory Matrix4.skew(double alpha, double beta)
// 沿着x軸扭曲
factory Matrix4.skewX(double alpha)
// 沿着y軸扭曲
factory Matrix4.skewY(double beta)
// 移動矩陣
factory Matrix4.translation(Vector3 translation)
// 移動矩陣, 參數不一樣而已
factory Matrix4.translationValues(double x, double y, double z)
// 全是0的4*4的張量
factory Matrix4.zero()
複製代碼
Container
是一個容器類widget
,它自己不對應具體的RenderObject
,它是DecoratedBox
、ConstrainedBox
、Transform
、Padding
、Align
等widget
的一個組合widgetContainer
能夠實現同時須要裝飾、變換、限制的場景Container
的相關定義Container({
Key key,
// 對其方式
this.alignment,
// 內邊距
this.padding,
// 背景顏色
Color color,
// 背景裝飾
Decoration decoration,
// 前景裝飾
this.foregroundDecoration,
double width,
double height,
//容器大小的限制條件
BoxConstraints constraints,
// 容器的外邊距, EdgeInsets
this.margin,
// 設置變換矩陣
this.transform,
this.child,
})
複製代碼
width
、height
屬性來指定,也能夠經過constraints
來指定,若是同時存在時,width
、height
優先。實際上Container
內部會根據width
、height
來生成一個constraints
color
和decoration
是互斥的,實際上,當指定color
時,Container
內會自動建立一個decoration
經過使用來實現以下效果
Container(
margin: EdgeInsets.only(top: 50.0, left: 120.0), //容器外補白
constraints: BoxConstraints.tightFor(width: 200.0, height: 150.0), //卡片大小
decoration: BoxDecoration(//背景裝飾
gradient: RadialGradient( //背景徑向漸變
colors: [Colors.red, Colors.orange],
center: Alignment.topLeft,
radius: .98
),
boxShadow: [ //卡片陰影
BoxShadow(
color: Colors.black54,
offset: Offset(2.0, 2.0),
blurRadius: 4.0
)
]
),
transform: Matrix4.rotationZ(.2), //卡片傾斜變換
alignment: Alignment.center, //卡片內文字居中
child: Text( //卡片文字
"5.20", style: TextStyle(color: Colors.white, fontSize: 40.0),
),
);
複製代碼
歡迎您掃一掃下面的微信公衆號,訂閱個人博客!