- Flutter and Dart series articles
- GitHub address of the project
- Container classes
Widget
And the layout of the classWidget
They all act on their childrenWidget
, the difference is:- Layout of the class
Widget
Usually you need to receive onewidget
Array (children
), they directly or indirectly inherit from (or contain)MultiChildRenderObjectWidget
- The container class
Widget
Generally, you only need to accept one coinWidget
(child
), they directly or indirectly inherit from (or contain)SingleChildRenderObjectWidget
- Layout of the class
Widget
It pairs its children in a certain arrangementWidget
To arrange - The container class
Widget
Generally just packaging the childWidget
, add some embellishment (fill or background color, etc.), transform (rotate or crop, etc.), or restrict (size, etc.).
- Layout of the class
Flutter
The authorities are not rightWidget
Official classification, our classification is mainly for the convenience of discussion and comparisonWidget
Function of differentiated memory- Related container classes
Widget
It is mainly divided into the following types- Fill class container
Padding
- Layout restriction class containers
ConstrainedBox
,SizeBox
- Decorative container
DecoratedBox
- Transformation class container
Transform
- Combination of the container
Container
- Navigation container
Scaffold
,TabBar
,AppBar
Etc.
- Fill class container
Padding
Padding allows you to set an inner margin for its child elements
class Padding extends SingleChildRenderObjectWidget {
const Padding({
Key key,
/ / padding
@required this.padding,
Widget child,
})
final EdgeInsetsGeometry padding;
}
Copy the code
EdgeInsetsGeometry is an abstract class that generally uses EdgeInsets. EdgeInsetsGeometry is a subclass of EdgeInsetsGeometry, and some methods are defined below
class EdgeInsets extends EdgeInsetsGeometry {
// Set margins according to upper, lower, left, and right
const EdgeInsets.fromLTRB(this.left, this.top, this.right, this.bottom);
// set four peripherals
const EdgeInsets.all(double value)
// Set only some of the margins
const EdgeInsets.only({
// The following are the default values
this.left = 0.0.this.top = 0.0.this.right = 0.0.this.bottom = 0.0
});
// According to the horizontal and vertical direction, the same spacing up and down, the same spacing left and right
const EdgeInsets.symmetric({ double vertical = 0.0.double horizontal = 0.0 })
// Static variables, up, down, left, and right, are 0
static const EdgeInsets zero = EdgeInsets.only();
}
Copy the code
The sample
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(20), child: Icon(Icons.phone, color: Colors.cyan,), ); }}Copy the code
ConstrainedBox
ConstrainedBox
andSizedBox
Is throughRenderConstrainedBox
To render theSizedBox
justConstrainedBox
A customConstrainedBox
Mainly used in pairswidget
Add additional constraints
class ConstrainedBox extends SingleChildRenderObjectWidget {
ConstrainedBox({
Key key,
@required this.constraints,
Widget child
})
/// Add constraints to the child widgets
final BoxConstraints constraints;
Copy the code
BoxConstraints
BoxConstraints sets the constraints on the Widget by internally setting four properties: maximum/small width and maximum size height. The associated constructors and instance functions are shown below
class BoxConstraints extends Constraints {
/// constructor
const BoxConstraints({
// Minimum width
this.minWidth = 0.0.// Maximum width
this.maxWidth = double.infinity,
// Minimum height
this.minHeight = 0.0.// Maximum height
this.maxHeight = double.infinity
});
// set the constraint based on the specified Size
BoxConstraints.tight(Size size)
: minWidth = size.width,
maxWidth = size.width,
minHeight = size.height,
maxHeight = size.height;
// According to the specified width and height Settings, the parameter can be null
const BoxConstraints.tightFor({
double width,
doubleheight }): minWidth = width ! =null ? width : 0.0, maxWidth = width ! =null ? width : double.infinity, minHeight = height ! =null ? height : 0.0, maxHeight = height ! =null ? height : double.infinity;
// The default width and height are the maximum, and the parameter can be null
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;
// Set the maximum value and minimum value to 0 according to the Size parameter
BoxConstraints.loose(Size size)
: minWidth = 0.0,
maxWidth = size.width,
minHeight = 0.0,
maxHeight = size.height;
// Depending on the width and height, if the parameter is empty, the default value is the maximum value
const BoxConstraints.expand({
double width,
doubleheight }): minWidth = width ! =null ? width : double.infinity, maxWidth = width ! =null ? width : double.infinity, minHeight = height ! =null ? height : double.infinity, maxHeight = height ! =null ? height : double.infinity;
}
Copy the code
Using the instance
class ConstrainedBoxView extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return ConstrainedBox(
constraints: BoxConstraints(
minWidth: double.infinity, // Set the width to the maximum
minHeight: 50.// The minimum height is set to 50
),
child: Container(
height: 10.// Set the height to 10child: DecoratedBox(decoration: BoxDecoration(color: Colors.orange)), ), ); }}Copy the code
- As you can see, although will
Container
The height is set to 10 pixels, but it ends up being 50 pixels, which is exactly what it isConstrainedBox
The minimum height limit is in effect - If you have
Container
Set the height of the red area to 80 pixels, because in this example,ConstrainedBox
Only the minimum height is restricted, not the maximum height
SizedBox
The SizedBox is used to specify a fixed width and height for the child widgets
// Several constructors for SizedBox
class SizedBox extends SingleChildRenderObjectWidget {
/// Set a fixed height
const SizedBox({ Key key, this.width, this.height, Widget child })
: super(key: key, child: child);
// create a box with the maximum width and height
const SizedBox.expand({ Key key, Widget child })
: width = double.infinity,
height = double.infinity,
super(key: key, child: child);
/// create a box with minimum width and height (both 0)
const SizedBox.shrink({ Key key, Widget child })
: width = 0.0,
height = 0.0.super(key: key, child: child);
// create a box with the specified size
SizedBox.fromSize({ Key key, Widget child, Size size })
: width = size?.width,
height = size?.height,
super(key: key, child: child);
}
Copy the code
Here we create a Widget that specifies the width and height
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)), ), ); }}// In fact SizedBox and just ConstrainedBox are a custom, the above code is equivalent to
ConstrainedBox(
constraints: BoxConstraints.tightFor(width: 80.0,height: 80.0),
child: Container(
child: DecoratedBox(decoration: BoxDecoration(color: Colors.orange)),
),
)
Copy the code
In fact, ConstrainedBox and SizedBox are rendered with RenderConstrainedBox, We can see that ConstrainedBox and the SizedBox createRenderObject() method both return a RenderConstrainedBox object
// 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;
}
Copy the code
Multiple constraint problem
- If one of them
widget
There is more than one parentConstrainedBox
limit - for
minWidth
andminHeight
For example, take the parent with the largest corresponding value. Only in this way can we ensure that the parent restriction does not conflict with the child restriction - for
maxWidth
andmaxHeight
It doesn’t work, it ends up being 0 in width and height
UnconstrainedBox
const UnconstrainedBox({
Key key,
Widget child,
// TextDirection, which represents the layout order of the horizontal child widgets
this.textDirection,
// How the child widgets are aligned on the main axis
this.alignment = Alignment.center,
// Set the constraint's Axis, horizontal or vertical, Axis. Horizontal
this.constrainedAxis,
})
Copy the code
UnconstrainedBox
Won’t pairWidget
Produces any restrictions that allow its childrenWidget
Draw it to its own size- In general, we rarely use this directly
widget
But it might be helpful to “remove” multiple restrictions
ConstrainedBox(
constraints: BoxConstraints(
minWidth: 60,
minHeight: 100,
),
child: UnconstrainedBox( // "remove" the parent limit
textDirection: TextDirection.ltr,
alignment: Alignment.center,
constrainedAxis: Axis.horizontal,
child: ConstrainedBox(
constraints: BoxConstraints(
minWidth: 90,
minHeight: 20,
),
child: DecoratedBox(decoration: BoxDecoration(color: Colors.red)),
),
)
);
Copy the code
- In the code above, if there is no middle
UnconstrainedBox
According to the multiple restrictions rule described above, a red box of 90×100 will be displayed - But because the
UnconstrainedBox
“Remove” the fatherConstrainedBox
Limit, then will eventually according to the childConstrainedBox
Limit to draw the red box, i.e. 90×20:
- But be careful,
UnconstrainedBox
The “removal” of the parent constraint is not a true removal; in the example above, although the red area is 90×20, there is still 80 blank space above it. - In other words, father-limited
minHeight
(100.0) is still valid, but it does not affect the size of the final child element, but it still occupies the corresponding space and can be considered the parentConstrainedBox
Theta operates on phiConstrainedBox
On, and the red box only accepts the sonConstrainedBox
Limit, this point please readers must pay attention to - And there’s no way to get rid of the father, right
BoxConstraints
The limits of - In defining a generic
widget
When, if pairwidget
Be careful when specifying restrictions, because once you specify restrictions, the childwidget
If you want to do the relevant custom size will be very difficult, because the childwidget
Do not change the parentwidget
Can’t completely remove its restriction condition
DecoratedBox
The DecoratedBox can draw a Decoration (such as background, border, gradient, etc.) before (or after) its child widget
const DecoratedBox({
Key key,
@required this.decoration,
this.position = DecorationPosition.background,
Widget child
})
Copy the code
decoration
: represents the decoration to be painted, of typeDecoration
Is an abstract class that defines an interfacecreateBoxPainter()
The primary responsibility of a subclass is to implement it to create a decorator, so we’ll use it laterBoxDecoration
To implement the propertyposition
This property determines where to drawDecoration
It receivesDecorationPosition
The enumeration class has two values:background
: in the childwidget
Draw after, that is, background decoration (default)foreground
: in the childwidget
Painted above, that is, the foreground
BoxDecoration
BoxDecoration is a subclass of Decoration, which is usually used to implement properties similar to Decoration
const BoxDecoration({
// Background color
this.color,
// Background image, DecorationImage
this.image,
/ / frame
this.border,
/ / the rounded
this.borderRadius,
/ / the shadow
this.boxShadow,
/ / gradients
this.gradient,
// BlendMode is the blend rendering mode of the background color and the background image
this.backgroundBlendMode,
/ / shape
this.shape = BoxShape.rectangle,
})
Copy the code
image
Set the background image DecorationImage
const DecorationImage({
/ / ImageProvider type
@required this.image,
this.colorFilter,
this.fit,
this.alignment = Alignment.center,
this.centerSlice,
this.repeat = ImageRepeat.noRepeat,
this.matchTextDirection = false,})Copy the code
image
- The way the image is set, yes
ImageProvider
The type of ImageProvider
Is an abstract class that needs to be implemented using subclassesNetworkImage
FileImage
MemoryImage
colorFilter
- The color filter applied to the image before drawing it, the property value is
ColorFilter
class ColorFilter
The constructor has two properties that set the color image and the picture image, which will also be used later to explain the enumeration values
// Set the color image and the image image respectively
const ColorFilter.mode(Color color, BlendMode blendMode)
Copy the code
BlendMode has the following enumeration values, with SRC indicating that the image is not displayed, and DST indicating that the color image is not displayed
blendMode |
Enumeration value meaning |
---|---|
clear |
Color images and picture images are not displayed |
src |
Show color images do not show picture images |
dst |
Display picture images do not display color images |
srcOver |
The color image is above the picture image |
dstOver |
The color image is below the picture image |
srcIn |
Displays a picture image, but only what overlaps with the color image. |
dstIn |
Display the color image, but only the overlap with the image image (the intersection of the two) |
srcOut |
Display the picture image, but only the parts that do not coincide with the color image (the difference between the two) |
dstOut |
Display color image, but only display and image image does not coincide with the part (the difference between the two), generally empty |
srcATop |
Synthesize the picture image onto the color image, only the intersection part |
dstATop |
Composes the color image onto the picture image, only the intersection part |
xor |
Image image and color image composition results |
plus |
Image and color composition, but affected by transparency |
modulate |
Multiply the color components of the picture image and the color image. This can only produce the same or darker color (multiply by white, 1.0, the result remains the same; Multiplied by black, 0.0, the result is black |
screen |
Multiply the reciprocal of the color components of the picture image and the color image and reverse the result |
overlay |
After adjusting the components of the picture image and color image to favor the target, multiply them |
darken |
Compose a picture image and a color image by selecting the lowest value from each color channel |
lighten |
Compose picture images and color images by selecting the highest value from each color channel |
There are several enumerated values, but I really don’t know how to explain the above explanation seems to is not very clear, vaguely, suggest you see the effect self-test PIC, or look at the official documents, also have renderings, actually a lot of enumeration values or use less than, if there is a good explanation, Suggestions are welcome at……… Embarrassment of capitals
border
To set the style of the border,BoxBorder is an abstract class with three implementations of the following two classes
// Two implementations of 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,
})
}
// Below is the BorderSide constructor, which was introduced in the previous text but is not covered here
class BorderSide {
const BorderSide({
this.color = const Color(0xFF000000),
this.width = 1.0.this.style = BorderStyle.solid,
})
}
// BorderDirectional's constructor
class BorderDirectional extends BoxBorder {
const BorderDirectional({
this.top = BorderSide.none,
this.start = BorderSide.none,
this.end = BorderSide.none,
this.bottom = BorderSide.none,
})
}
Copy the code
boxShadow
Set the box’s shadows, which match the box’s shape, and accept a list of stored BoxShadows. Let’s look at the BoxShadow constructor
const BoxShadow({
/ / color
Color color = const Color(0xFF000000),
// The offset of the shadow relative to the box
Offset offset = Offset.zero,
// The blur degree of the shadow, the larger the value, the more blurred the shadow
double blurRadius = 0.0.// The shadow increases the pixel value in the opposite direction
this.spreadRadius = 0.0
})
// Add shadows to all four edges
[
BoxShadow(color: Colors.grey, offset: Offset(- 5.- 5), blurRadius: 10, spreadRadius: 0),
BoxShadow(color: Colors.red, offset: Offset(5.5), blurRadius: 10, spreadRadius: 0)],Copy the code
gradient
Set the background color to Gradient, which is an abstract class, and there are three subclasses below
LinearGradient
RadialGradient
SweepGradient
// Linear gradient
const LinearGradient({
/ / starting point
this.begin = Alignment.centerLeft,
/ / the end
this.end = Alignment.centerRight,
// Array of color values
@required List<Color> colors,
// List of values, containing values from 0.0 to 1.0
List<double> stops,
// Gradient tiling mode, specify tiling mode in areas other than the start and end
this.tileMode = TileMode.clamp,
})
// Circle gradient,
const RadialGradient({
// Center of gradient)
this.center = Alignment.center,
// The radius of the gradient is a floating-point number multiplied by the width of the box
this.radius = 0.5.@required List<Color> colors,
List<double> stops,
this.tileMode = TileMode.clamp,
this.focal,
this.focalRadius = 0.0
})
const SweepGradient({
// The center point of the position
this.center = Alignment.center,
// Angle of the starting point
this.startAngle = 0.0.// The Angle of the end
this.endAngle = math.pi * 2.@required List<Color> colors,
List<double> stops,
this.tileMode = TileMode.clamp,
})
Copy the code
The three gradient effects are shown below
In LinearGradient, the effects of each enumerated value of TileMode are as follows
shape
Sets the shape of the background. BoxShape is an enumerated value for the background color, background image, and gradient
enum BoxShape {
// Keep the same
rectangle,
// Clipping to a circle conflicts with the borderRadius property
circle,
}
Copy the code
Transform
Transform
Can be in the childWidget
When you draw it, you apply a matrix transformation to itchild
Do translation, rotation, scaling and other operationsMatrix4
Is a 4D matrix through which various matrix operations can be implemented
Transform
Let’s take a look at some of the constructors for Transform
class Transform extends SingleChildRenderObjectWidget {
// Create a matrix transform Widget
const Transform({
Key key,
// The matrix performs transformations that accept a Matrix4 object
@required this.transform,
// The rotation point, offset from the top left vertex. The default rotation point is the top left vertex,
// Accept an Offset object
this.origin,
// To its way
this.alignment,
// The click area should also be changed accordingly
this.transformHitTests = true,
Widget child,
})
// Create a rotation transformation matrix
Transform.rotate({
Key key,
// Set the rotation Angle
@required double angle,
this.origin,
this.alignment = Alignment.center,
this.transformHitTests = true,
Widget child,
})
// Create a translation matrix
Transform.translate({
Key key,
@required Offset offset,
this.transformHitTests = true,
Widget child,
})
// Create a scaling matrix
Transform.scale({
Key key,
// Set the scale from 0 to 1
@required double scale,
this.origin,
this.alignment = Alignment.center,
this.transformHitTests = true,
Widget child,
})
}
Copy the code
Below are concrete examples of each form of transformation
rotating
Transform.rotate Can rotate child widgets as shown in the following code
Container(
color: Colors.black,
child: Transform.rotate(
☞ Angle of rotation, math. PI refers to 180 degrees
angle: -math.pi / 4,
child: Container(
padding: const EdgeInsets.all(8.0),
color: const Color(0xFFE8581C),
child: const Text('https://titanjun.top'),)))Copy the code
translation
Transform.translate receives an offset argument that can be translated to the child widget by a specified distance along the X and y axes when drawing
Container(
color: Colors.black,
child: Transform.translate(
// The default origin is the upper left corner, shifted 5 pixels to the right, shifted 15 pixels down
offset: const Offset(5.0.15.0),
child: Container(
padding: const EdgeInsets.all(8.0),
color: const Color(0xFF7F7F7F),
child: const Text('Quarter'),)))Copy the code
The zoom
Transform.scale can be used to shrink or enlarge child widgets
Container(
color: Colors.black,
child: Transform.scale(
origin: Offset(5.5),
// Shrink by 0.5 times
scale: 0.5,
child: Container(
padding: const EdgeInsets.all(8.0),
color: const Color(0xFFE8581C),
child: const Text('Bad Ideas'),)))Copy the code
Pay attention to the point
Transform
The transformation is applied to the drawing phase, not to the layout (layout
) phase- So no matter what changes are applied to the child widget, the amount of space it takes up and its position on the screen remain constant, because these are determined during the layout phase
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
DecoratedBox(
decoration:BoxDecoration(color: Colors.red),
child: Transform.scale(scale: 1.5,
child: Text("Hello world")
)
),
Text("Hello", style: TextStyle(color: Colors.green, fontSize: 18.0),) ",Copy the code
- Because of the first one
Text
After applying transformation (magnification), it will be enlarged when drawing, but it still takes up the space of the red part, so the secondtext
It’s going to be right next to the red, and eventually there’s going to be some overlap. - Since matrix changes only affect the drawing stage, in some scenarios, when UI needs to be changed, visual UI changes can be directly achieved through matrix changes without re-triggering the build process, which will save money
layout
Overhead, so the performance will be better - As introduced earlier
Flow widget
Internally, it’s updating the UI with matrix transformations, and other than that,Flutter
The animationwidget
Is also widely used inTransform
To improve performance
RotatedBox
RotatedBox
andTransform.rotate
Functionally similar, they can both be pairedwidget
Perform the rotation transform, but with one difference:RotatedBox
The transformation of phi is zerolayout
The phase will affect the subwidget
The location and size of- We will introduce it above
Transform.rotate
Change the example of
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
DecoratedBox(
decoration: BoxDecoration(color: Colors.red),
Transform. Rotate to RotatedBox
child: RotatedBox(
/ / int type
quarterTurns: 1.// Rotate 90 degrees (1/4 turn)
child: Text("Hello world"),
),
),
Text("Hello", style: TextStyle(color: Colors.green, fontSize: 18.0),),),Copy the code
Since the RotatedBox is applied to the layout stage, the widget is rotated 90 degrees (not just the content), and the decoration is applied to the actual space occupied by the widget, so it looks like the image above. You can compare this to the previous transform.rotate example
Matrix4
A 4D Transform matrix, a Transform uses Matrix4 to Transform its child widgets
// 4 x 4 matrix
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)
// Set a new matrix
factory Matrix4.columns(Vector4 arg0, Vector4 arg1, Vector4 arg2, Vector4 arg3)
// Combine translation, rotation and scaling to form a new transformation matrix
factory Matrix4.compose(Vector3 translation, Quaternion rotation, Vector3 scale)
// Copy a 4*4 tensor (matrix)
factory Matrix4.copy(Matrix4 other)
Vector3(double x, double y, double z)
factory Matrix4.diagonal3(Vector3 scale)
// Scale matrix, just with different parameters
factory Matrix4.diagonal3Values(double x, double y, double z)
Matrix4.fromBuffer(ByteBuffer buffer, int offset)
// Construct Matrix4 using the given Float64List
Matrix4.fromFloat64List(Float64List _m4storage)
// Convert a 16-bit one-dimensional array into a 4*4 matrix
factory Matrix4.fromList(List<double> values)
// Restore the original state, which is the 4*4 identity matrix
factory Matrix4.identity()
// Take the opposite matrix
factory Matrix4.inverted(Matrix4 other)
// Merge the product of two 4-dimensional vectors
factory Matrix4.outer(Vector4 u, Vector4 v)
// Rotate around the X-axis
factory Matrix4.rotationX(double radians)
// Rotate around the Y axis
factory Matrix4.rotationY(double radians)
// Rotate around the z-axis
factory Matrix4.rotationZ(double radians)
// Contort transform
factory Matrix4.skew(double alpha, double beta)
// Along the X-axis
factory Matrix4.skewX(double alpha)
// Along the Y-axis
factory Matrix4.skewY(double beta)
// Move the matrix
factory Matrix4.translation(Vector3 translation)
// Move the matrix with different parameters
factory Matrix4.translationValues(double x, double y, double z)
// a 4*4 tensor with all zeros
factory Matrix4.zero()
Copy the code
Container
Container
Is a container classwidget
It doesn’t correspond to specificRenderObject
, it isDecoratedBox
,ConstrainedBox
,Transform
,Padding
,Align
Etc.widget
A composite widget of- So we only have to go through one
Container
You can achieve scenes that need to be decorated, transformed, and restricted at the same time - The following is
Container
Related definitions of
Container({
Key key,
// To its way
this.alignment,
/ / padding
this.padding,
// Background color
Color color,
// Background decoration
Decoration decoration,
// Foreground decoration
this.foregroundDecoration,
double width,
double height,
// Constraints on the size of the container
BoxConstraints constraints,
// The container margin, EdgeInsets
this.margin,
// Set the transformation matrix
this.transform,
this.child,
})
Copy the code
- The size of the container can be passed
width
,height
Property, can also be specified byconstraints
To specify that, if both exist,width
,height
Is preferred. In factContainer
Internal will be based onwidth
,height
To generate aconstraints
color
anddecoration
Is mutually exclusive, in fact, when specifiedcolor
When,Container
Will automatically create onedecoration
Using the instance
Use it to achieve the following effects
Container(
margin: EdgeInsets.only(top: 50.0, left: 120.0), // Fill the container
constraints: BoxConstraints.tightFor(width: 200.0, height: 150.0), // Card size
decoration: BoxDecoration(// Background decoration
gradient: RadialGradient( // Background radial gradient
colors: [Colors.red, Colors.orange],
center: Alignment.topLeft,
radius: 98.
),
boxShadow: [ // Card shadow
BoxShadow(
color: Colors.black54,
offset: Offset(2.0.2.0),
blurRadius: 4.0
)
]
),
transform: Matrix4.rotationZ(2.), // The card tilts
alignment: Alignment.center, // The text inside the card is centered
child: Text( // The card text
"5.20", style: TextStyle(color: Colors.white, fontSize: 40.0),),);Copy the code
reference
- Flutter container Widget– Chinese Version
- Flutter website
Please scan the following wechat official account and subscribe to my blog!