本文由 简悦SimpRead 转码,原文地址 alfonso-software.medium.com
在这个故事中,你会发现有4个挑战可以尝试,还有一些例子可以学习集装箱widge......。
在这个故事中,你会发现有4个挑战可以尝试,还有一些例子可以学习容器小部件的知识。如何对齐、装饰和组合容器。
目录
-
挑战
-
实例和理论
- 定义
- 容器部件的基本使用 容器部件的基本使用
- 给出一个宽度和高度,并对齐它的孩子。
- 中心和对齐小组件
- 居中小组件
- 使用一个预定义的值来对齐小组件
- 使用宽度和高度因素对准小组件
- 装饰
- 圆角
- 圆角:跑道形状
- 圆角(只有部分圆角)
- 圆角形状
- 边界
- 阴影
- 双色线性渐变
- 基本的双色线性梯度,带止点的梯度
- 组成的容器
- 子部件有一个高度和宽度
- 子部件有高度但没有宽度
- 子部件没有高度也没有宽度
- 子部件没有宽度,但有限制(边距)。
NOTE: Transform widget和transform container-property 将在接下来的故事中介绍。请不要错过它们!
挑战
享受以下的挑战,并认真对待它们。它们会提高你的水平!!。
记住,如果你在解决这些挑战时遇到问题或有疑问,可以先尝试阅读一些理论和例子,你可以在它们之后找到。
挑战1
挑战说明
你所面临的挑战是创造一个类似于_登陆直升机区的设计(下面的截图)。
你不应该:
- 使用与我相同的颜色或相同的字体大小
你应该:
- 将设计与屏幕的顶部中心对齐
- 设置一个顶部边缘线,将其与AppBar分开。
- 将文本 "H "与父容器的中心对齐。
- 只使用
Align、Container和Text小组件的实例,以及它们的属性
现在,停止阅读,在看到我的解决方案之前,试着自己做一下。
祝您好运!
我的方案
这不是唯一可能的解决方案,这只是我的解决方案...
Align(
alignment: Alignment.topCenter,
child: Container(
margin: EdgeInsets.only(top: 20),
decoration: BoxDecoration(
shape: BoxShape.circle,
border: Border.all(
color: Colors.orange,
width: 10,
),
),
width: 280,
height: 280,
alignment: Alignment.center,
child: Text(
'H',
style: TextStyle(
fontSize: 180,
color: Colors.orange,
),
),
),
)
挑战2
挑战说明
试着创造这个设计,尽可能的相似。
你不应该:
- 使用相同的背景颜色或相同的字体大小,或相同的边框半径,因为我已经使用了。
你应该:
- 只使用 "容器 "和 "文本 "部件的实例和它们的属性。
现在,停止阅读,在看到我的解决方案之前,试着自己做一下。
祝您好运!
我的方案
这不是唯一可能的解决方案,这只是我的解决方案...
Container(
height: 130,
width: double.infinity,
decoration: BoxDecoration(
color: Color(0xFF57B3FC),
borderRadius: BorderRadius.only(
bottomRight: Radius.circular(50),
bottomLeft: Radius.circular(50),
),
boxShadow: [
BoxShadow(
color: Color(0xAA6EB1E6),
offset: Offset(9, 9),
blurRadius: 6,
),
],
),
alignment: Alignment.center,
child: Text(
'I am a header',
style: TextStyle(
fontSize: 38,
color: Colors.white,
),
),
)
挑战3
挑战说明
尝试创建下面的设计,尽可能的相似。
你不应该:
- 使用与我相同的颜色、相同的尺寸或相同的边框半径
你应该:
- 只使用 "Container "部件的实例和它的属性。
现在,停止阅读,在看到我的解决方案之前,试着自己做一下。
祝您好运!
我的方案
这并不是唯一可能的解决方案,这只是我的解决方案...
Container(
margin: EdgeInsets.all(40),
width: 300,
height: 90,
alignment: Alignment.centerLeft,
decoration: BoxDecoration(
color: Color(0xFF4AAEFD), //blue
borderRadius: BorderRadius.circular(45),
),
child: Container(
width: 210,
height: 90,
decoration: BoxDecoration(
color: Color(0xFF94CCF9), //light blue
borderRadius: BorderRadius.only(
topLeft: Radius.circular(45),
bottomLeft: Radius.circular(45),
),
),
alignment: Alignment.center,
child: Text(
'Challenge',
style: TextStyle(
fontSize: 32,
color: Colors.white,
),
),
),
)
为了得到一个跑道形状的效果,我们使用一个足够大的值作为border-radius。大于或等于高度的一半。
由于容器小组件是一个单子布局小组件,它只能有一个孩子。所以的关键是创建蓝色的容器,然后创建浅蓝色的容器作为蓝色容器的孩子。最后,我们将创建文本小组件作为最后这个浅蓝色小组件的孩子。
挑战4
挑战说明
尝试实现下面的设计。
你不应该:
- 使用相同的颜色或相同的尺寸或相同的边框半径,因为我已经使用了
你应该:
- 只使用 "容器 "和 "文本 "小组件的实例和它们的属性。
- 将橙色的容器对准屏幕的顶部中心位置
- 通过在橙色容器周围留出空白,使其尽可能地宽。
请注意:
- 橙色的容器有一个精细的面向左下角的阴影。
现在,停止阅读,在看到我的解决方案之前,试着自己做一下。
祝您好运!
我的方案
这并不是唯一可能的解决方案,这只是我的解决方案...
首先,我们创建一个父容器,它给我们提供填充屏幕的颜色背景。
class Challenge extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
color: Color(0xFF272A3C),
width: double.infinity,
height: double.infinity,
alignment: Alignment.topCenter, //to align its child
child: CardContainer(),
);
}
}
然后我们为我们的自定义容器写代码,称为CardContainer。
class CardContainer extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.all(30),
height: 160,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(20),
gradient: new LinearGradient(
colors: [
Color(0xFFFF422C),
Color(0xFFFF9003),
],
begin: Alignment.centerLeft,
end: Alignment.centerRight,
stops: [0.25, 0.90],
),
boxShadow: [
BoxShadow(
color: Color(0xFF101012),
offset: Offset(-12, 12),
blurRadius: 8,
),
],
),
alignment: Alignment.centerLeft, //to align its child
padding: EdgeInsets.all(20),
child: Text(
'Challenge',
style: TextStyle(
fontSize: 46,
color: Colors.white,
fontWeight: FontWeight.w200,
fontStyle: FontStyle.italic,
),
),
);
}
}
你有没有花时间去尝试这些挑战?如果是这样,恭喜你! 这就是方法!
实例和理论
阅读下面的理论和例子,了解背景和想法,帮助你解决前面的挑战。
当涉及到布局任务时,容器小部件是一个有用的小部件。我们可以用它来装饰(添加一些背景样式),组成,并定位一个子部件。
它是一个单子布局小组件(它只有一个孩子)。
Container的基础用法
首先,我们只使用一个文本小组件...
Text(
'I am a text',
style: TextStyle(
fontSize: 38,
color: Color(0xFF04589A),
),
)
让我们把文本小组件包裹在一个没有颜色或装饰的容器小组件中,看看与之前的例子有什么不同。只有文本是可见的。
Container(
child: Text(
'I am a text',
style: TextStyle(
fontSize: 38,
color: Color(0xFF04589A),
),
),
)
在容器中添加颜色。
Container(
color: Color(0xFF94CCF9),
child: Text(
'I am a text',
style: TextStyle(fontSize: 38, color: Color(0xFF04589A)),
),
)
让我们添加一些边距,将容器与左上角分开,并添加一些填充,将文本与容器边框分开。
Container(
color: Color(0xFF94CCF9),
padding: const EdgeInsets.all(20),
margin: const EdgeInsets.only(left: 40, top: 40),
child: Text(
'I am a text',
style: TextStyle(fontSize: 38, color: Color(0xFF04589A)),
),
)
给定宽度和高度,并对齐子控件
容器首先用padding(通过decoration中的任何边框膨胀)包围孩子,然后在填充的范围内应用额外的constraints(将
width和height作为约束,如果两者都不是空的)。然后,容器被margin描述的额外的空白空间所包围。
因此,如果我们不设置容器的宽度和高度,这将是尽可能小的,用填充物包裹孩子。
但如果我们定义了容器的宽度和高度,容器就会尊重这些尺寸。而且,孩子会在容器内默认对齐到左上角,正如你在下面的例子中看到的那样。
Container(
color: Color(0xFF94CCF9),
padding: const EdgeInsets.all(15),
margin: const EdgeInsets.only(left: 40, top: 40),
width: 250,
height: 250,
child: Text(
'Text',
style: TextStyle(fontSize: 32, color: Color(0xFF04589A)),
),
)
我们可以在容器内改变孩子的对齐方式(对齐属性)。
Container(
color: Color(0xFF94CCF9),
padding: const EdgeInsets.all(15),
margin: const EdgeInsets.only(left: 40, top: 40),
width: 250,
height: 250,
alignment: Alignment.bottomRight,
child: Text(
'Text',
style: TextStyle(fontSize: 32, color: Color(0xFF04589A)),
),
)
我们可以通过用两个新的部件来包装我们的容器,使其在其父体中居中或对齐。Center和Align。
中心和对齐Widget
中心Widget
Center(
child: Container(
color: Color(0xFF94CCF9),
padding: const EdgeInsets.all(15),
child: Text(
'I am a text',
style: TextStyle(
fontSize: 38,
color: Color(0xFF04589A),
),
),
),
)
使用一个预定义的值来对齐部件
使用一个预定义的值来对齐,比如。
- topLeft
- topCenter
- topRigth
- centerLeft
- center
- centerRigth
- bottomLeft
- bottomCenter
- bottomRight
Align(
alignment: Alignment.bottomLeft, //Alignment(-1.0, 1.0)
child: Container(
....
),
)
使用宽度和高度因素对齐部件
在构造函数中使用双倍的widthFactor和heightFactor的值来对齐到父部件内部的具体位置。
这两个因子,在其相应的尺寸中,从-1.0值到1.0值。
例如,当涉及到widthFactor:-1.0是左边界,0.0是中心,1.0是右边界。再进一步说,-0.5意味着左边界和中心之间的中间点......
Align(
alignment: Alignment(-0.5, 0.75),
child: Container(
....
),
)
装饰
我们可以用容器做的另一件事是装饰。我们将使用decoration属性来做。
有几个选项可以选择decoration值。
- BoxDecoration
- FlutterLogoDecoration
- ShapeDecoration
- UnderlineTableIndicator
这里我们将使用 BoxDecoration 类来做。
BoxDecoration是对如何绘制一个盒子的不可改变的描述,并提供了各种绘制盒子的方法。
我们可以选择一个颜色背景,一个图像背景,一个形状,一个边框,一个角的形状(borderRadius),一个阴影,以及一个渐变。
这并不是对使用这些属性的详尽描述,而只是给出了一些使用的例子。
如果我们在一个容器中使用装饰属性,那么容器的颜色属性 必须在 装饰类里面。
圆角
我们将通过使用 BoxDecoration 的boderRadius属性来表示圆角。
Container(
margin: EdgeInsets.all(40),
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Color(0xFF9DF09E),
borderRadius: BorderRadius.circular(20),
),
child: Text(
'I am a text',
style: TextStyle(
fontSize: 38,
color: Color(0xFF1F9221),
),
),
)
圆角:跑道形状
我们说 "跑道形状 "是指边框半径大到足以在每一侧(左和右)实现一个完整的垂直圆角形状。
我们可以给它一个大值作为border-radius。
Container(
margin: EdgeInsets.all(40),
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Color(0xFFF8DAA0),
borderRadius: BorderRadius.circular(500),
),
child: Text(
'I am a text',
style: TextStyle(
fontSize: 38,
color: Color(0xFFEC9B02),
),
),
)
圆角(只有部分圆角)
Container(
margin: EdgeInsets.all(40),
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Colors.purple,
borderRadius: BorderRadius.only(
topRight: Radius.circular(40.0),
bottomLeft: Radius.circular(40.0),
),
),
child: Text(
'I am a text',
style: TextStyle(
fontSize: 38,
color: Colors.white,
),
),
)
循环形状
我们将使用一个BoxShape作为shape属性。
Container(
margin: EdgeInsets.all(30),
decoration: BoxDecoration(
color: Colors.purpleAccent,
shape: BoxShape.circle,
),
width: 150,
height: 150,
)
边界
Container(
margin: EdgeInsets.all(40),
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Color(0xFF94CCF9),
border: Border.all(
color: Color(0xFF04589A),
width: 4,
),
borderRadius: BorderRadius.circular(10.0),
),
child: Text(
'I am a text',
style: TextStyle(
fontSize: 38,
color: Color(0xFF04589A),
),
),
)
阴影
Container(
margin: EdgeInsets.all(40),
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Color(0xFF94CCF9),
borderRadius: BorderRadius.circular(30.0),
boxShadow: [
BoxShadow(
color: Color(0xFF04589A),
offset: Offset(7, 7),
blurRadius: 6,
),
],
),
child: Text(
'I am a text',
style: TextStyle(
fontSize: 38,
color: Color(0xFF04589A),
),
),
)
我们通过使用boxShadow属性来设置一个阴影效果。在BoxShadow里面,我们使用offset属性来告诉阴影的位移。我们还可以添加模糊来获得更真实的效果。
前面的截图显示了一个太强的阴影(颜色0xFF04589A)。
如果我们降低一点不透明度,例如从0xFF04589A到0x9904589A,我们会得到一个更好的结果。让我们看看!
双色线性梯度
Container(
margin: EdgeInsets.all(40),
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Color(0xFF94CCF9),
border: Border.all(
color: Color(0xFF04589A),
width: 4,
),
borderRadius: BorderRadius.circular(10.0),
gradient: LinearGradient(
colors: [Colors.white, Color(0xFF75C0FC)],
begin: Alignment.centerLeft,
end: Alignment.centerRight),
),
child: Text(
'I am a text',
style: TextStyle(fontSize: 38, color: Color(0xFF04589A)),
),
)
带停顿的双色线性渐变
梯度止点是一个从0.0到1.0的数值列表,表示梯度上的分数。
在前面的例子中,我们没有使用止点。这与使用止点[0.0, 1.0] 是一样的。
那么,使用不同的止点值呢?让我们看几个例子!
为了让左边的颜色(白色)更加重要,我们为第一个停止点提供一个大于0.0的值。
Container(
margin: EdgeInsets.all(40),
padding: EdgeInsets.all(20),
decoration: BoxDecoration(
color: Color(0xFF94CCF9),
border: Border.all(
color: Color(0xFF04589A),
width: 4,
),
borderRadius: BorderRadius.circular(10.0),
gradient: LinearGradient(
colors: [Colors.white, Color(0xFF75C0FC)],
begin: Alignment.centerLeft,
end: Alignment.centerRight,
stops: [0.4, 1.0],
),
),
child: Text(
'I am a text',
style: TextStyle(fontSize: 38, color: Color(0xFF04589A)),
),
)
为了达到相反的效果,我的意思是,看到更多的蓝色(右边的颜色)而不是白色(左边的颜色),我们选择一个低于1.0的值给第二站 [0.0, 0.6]。
在下面的例子中,我们可以看到一个美丽的线性梯度充满屏幕。
Center(
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.bottomLeft,
end: Alignment.topRight,
colors: [
Color(0xFFFBA3660),
Color(0xFF1C256E),
],
stops: [0.3, 0.75],
),
),
),
)
组合容器
组合容器是将一个容器设置在另一个容器内,或者换句话说,将一个容器设置为另一个容器的孩子。
子部件有一个高度和宽度
Container(
margin: const EdgeInsets.all(30),
decoration: BoxDecoration(
color: Colors.purple,
borderRadius: BorderRadius.circular(10.0),
),
width: 250,
height: 250,
alignment: Alignment.bottomCenter,
child: Container(
decoration: BoxDecoration(
color: Colors.cyan,
borderRadius: BorderRadius.circular(10.0),
),
height: 100,
width: 150,
),
)
青色容器已经被声明为紫色容器的一个孩子。
子部件被对齐到父部件的底部中心(父部件的对齐属性)。
子小组件有高度但没有宽度
Container(
margin: const EdgeInsets.all(30),
decoration: BoxDecoration(
color: Colors.purple,
borderRadius: BorderRadius.circular(10.0),
),
width: 250,
height: 250,
alignment: Alignment.bottomCenter,
child: Container(
decoration: BoxDecoration(
color: Colors.cyan,
borderRadius: BorderRadius.circular(10.0),
),
height: 100,
),
)
我们已经设置了孩子的高度,但没有设置孩子的宽度。然而,子部件(青色)完全覆盖了父部件的宽度。
如果容器部件没有孩子,没有
_高度_,没有_宽度_,没有 约束,也没有 对齐,但是父对象提供了有边界的约束,那么 容器 扩展以适应父对象提供的约束。
考虑到这一点,我们可以更好地解释前面截图中的青色小部件的行为。
- 青色的部件没有孩子,也没有宽度**,而父方,紫色的容器,提供了有边界的约束。我们的子青色容器填补了父体的水平尺寸,因为它没有宽度。
这个子部件没有高度和宽度。
Container(
margin: const EdgeInsets.all(30),
decoration: BoxDecoration(
color: Colors.purple,
borderRadius: BorderRadius.circular(10.0),
),
width: 250,
height: 250,
alignment: Alignment.bottomCenter,
child: Container(
decoration: BoxDecoration(
color: Colors.cyan,
borderRadius: BorderRadius.circular(10.0),
),
),
)
在这种情况下,子部件完全覆盖了父部件的宽度和高度,所以父部件(紫色部件)被子部件(青色部件) 隐藏。
子部件没有宽度,但有限制(margin)。
Container(
margin: const EdgeInsets.all(30),
decoration: BoxDecoration(
color: Colors.purple,
borderRadius: BorderRadius.circular(20.0),
),
width: 250,
height: 250,
alignment: Alignment.bottomCenter,
child: Container(
margin: const EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.cyan,
borderRadius: BorderRadius.circular(20.0),
),
height: 100,
),
)
子部件并没有完全覆盖父部件的宽度,因为我们在子部件中定义了一个10-dip的边距。
NOTE: Transform widget和transform container-property 将在接下来的故事中介绍。请不要错过它们!
如果你觉得这篇文章很有趣,或者它在某种程度上帮助了你,请给我很多👏.谢谢你阅读我的文章!