[Flutter翻译]Flutter Container的挑战

544 阅读13分钟

本文由 简悦SimpRead 转码,原文地址 alfonso-software.medium.com

在这个故事中,你会发现有4个挑战可以尝试,还有一些例子可以学习集装箱widge......。

image.png

在这个故事中,你会发现有4个挑战可以尝试,还有一些例子可以学习容器小部件的知识。如何对齐、装饰和组合容器。

目录

  1. 挑战

  2. 实例和理论

  • 定义
  • 容器部件的基本使用 容器部件的基本使用
  • 给出一个宽度和高度,并对齐它的孩子
  • 中心和对齐小组件
    • 居中小组件
    • 使用一个预定义的值来对齐小组件
    • 使用宽度和高度因素对准小组件
  • 装饰
    • 圆角
    • 圆角:跑道形状
    • 圆角(只有部分圆角)
    • 圆角形状
    • 边界
    • 阴影
    • 双色线性渐变
    • 基本的双色线性梯度,带止点的梯度
  • 组成的容器
    • 子部件有一个高度和宽度
    • 子部件有高度但没有宽度
    • 子部件没有高度也没有宽度
    • 子部件没有宽度,但有限制(边距)。

NOTE: Transform widget和transform container-property 将在接下来的故事中介绍。请不要错过它们!


挑战

享受以下的挑战,并认真对待它们。它们会提高你的水平!!

记住,如果你在解决这些挑战时遇到问题或有疑问,可以先尝试阅读一些理论和例子,你可以在它们之后找到。

挑战1

image.png

挑战说明

你所面临的挑战是创造一个类似于_登陆直升机区的设计(下面的截图)。

你不应该:

  • 使用与我相同的颜色或相同的字体大小

你应该:

  • 将设计与屏幕的顶部中心对齐
  • 设置一个顶部边缘线,将其与AppBar分开。
  • 将文本 "H "与父容器的中心对齐。
  • 只使用AlignContainerText小组件的实例,以及它们的属性

image.png

现在,停止阅读,在看到我的解决方案之前,试着自己做一下。

祝您好运!

我的方案

这不是唯一可能的解决方案,这只是我的解决方案...

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

image.png

挑战说明

试着创造这个设计,尽可能的相似。

你不应该:

  • 使用相同的背景颜色或相同的字体大小,或相同的边框半径,因为我已经使用了。

你应该:

  • 只使用 "容器 "和 "文本 "部件的实例和它们的属性。

image.png

现在,停止阅读,在看到我的解决方案之前,试着自己做一下。

祝您好运!

我的方案

这不是唯一可能的解决方案,这只是我的解决方案...

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

image.png

挑战说明

尝试创建下面的设计,尽可能的相似。

你不应该:

  • 使用与我相同的颜色、相同的尺寸或相同的边框半径

你应该:

  • 只使用 "Container "部件的实例和它的属性。

image.png

现在,停止阅读,在看到我的解决方案之前,试着自己做一下。

祝您好运!

我的方案

这并不是唯一可能的解决方案,这只是我的解决方案...

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

image.png

挑战说明

尝试实现下面的设计。

你不应该:

  • 使用相同的颜色或相同的尺寸或相同的边框半径,因为我已经使用了

你应该:

  • 只使用 "容器 "和 "文本 "小组件的实例和它们的属性。
  • 将橙色的容器对准屏幕的顶部中心位置
  • 通过在橙色容器周围留出空白,使其尽可能地宽。

请注意:

  • 橙色的容器有一个精细的面向左下角的阴影

image.png

现在,停止阅读,在看到我的解决方案之前,试着自己做一下。

祝您好运!

我的方案

这并不是唯一可能的解决方案,这只是我的解决方案...

首先,我们创建一个父容器,它给我们提供填充屏幕的颜色背景。

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,
        ),
      ),
    );
  }
}

image.png

你有没有花时间去尝试这些挑战?如果是这样,恭喜你! 这就是方法!


实例和理论

阅读下面的理论和例子,了解背景和想法,帮助你解决前面的挑战。

当涉及到布局任务时,容器小部件是一个有用的小部件。我们可以用它来装饰(添加一些背景样式),组成,并定位一个子部件。

它是一个单子布局小组件(它只有一个孩子)。

Container的基础用法

首先,我们只使用一个文本小组件...

image.png

Text(
  'I am a text',
  style: TextStyle(
    fontSize: 38,
    color: Color(0xFF04589A),
  ),
)

让我们把文本小组件包裹在一个没有颜色或装饰的容器小组件中,看看与之前的例子有什么不同。只有文本是可见的。

image.png

Container(
  child: Text(
    'I am a text',
    style: TextStyle(
      fontSize: 38,
      color: Color(0xFF04589A),
    ),
  ),
)

在容器中添加颜色

image.png

Container(
  color: Color(0xFF94CCF9),
  child: Text(
    'I am a text',
    style: TextStyle(fontSize: 38, color: Color(0xFF04589A)),
  ),
)

让我们添加一些边距,将容器与左上角分开,并添加一些填充,将文本与容器边框分开。

image.png

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(将widthheight作为约束,如果两者都不是空的)。然后,容器被margin描述的额外的空白空间所包围。

因此,如果我们不设置容器的宽度和高度,这将是尽可能小的,用填充物包裹孩子。

但如果我们定义了容器的宽度和高度,容器就会尊重这些尺寸。而且,孩子会在容器内默认对齐到左上角,正如你在下面的例子中看到的那样。

image.png

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)),
  ),
)

我们可以在容器内改变孩子的对齐方式(对齐属性)。

image.png

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)),
  ),
)

我们可以通过用两个新的部件来包装我们的容器,使其在其父体中居中或对齐。CenterAlign

中心和对齐Widget

中心Widget

image.png

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

image.png

Align(
  alignment: Alignment.bottomLeft, //Alignment(-1.0, 1.0)
  child: Container(
    ....
  ),
)

使用宽度和高度因素对齐部件

在构造函数中使用双倍的widthFactorheightFactor的值来对齐到父部件内部的具体位置。

这两个因子,在其相应的尺寸中,从-1.0值到1.0值。

例如,当涉及到widthFactor:-1.0是左边界,0.0是中心,1.0是右边界。再进一步说,-0.5意味着左边界和中心之间的中间点......

image.png

Align(
  alignment: Alignment(-0.5, 0.75),
  child: Container(
    ....
  ),
)

装饰

我们可以用容器做的另一件事是装饰。我们将使用decoration属性来做。

有几个选项可以选择decoration值。

  • BoxDecoration
  • FlutterLogoDecoration
  • ShapeDecoration
  • UnderlineTableIndicator

这里我们将使用 BoxDecoration 类来做。

BoxDecoration是对如何绘制一个盒子的不可改变的描述,并提供了各种绘制盒子的方法。

我们可以选择一个颜色背景,一个图像背景,一个形状,一个边框,一个角的形状(borderRadius),一个阴影,以及一个渐变。

这并不是对使用这些属性的详尽描述,而只是给出了一些使用的例子。

如果我们在一个容器中使用装饰属性,那么容器的颜色属性 必须在 装饰类里面。

圆角

我们将通过使用 BoxDecorationboderRadius属性来表示圆角。

image.png

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。

image.png

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),
    ),
  ),
)

圆角(只有部分圆角)

image.png

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属性。

image.png

Container(
  margin: EdgeInsets.all(30),
  decoration: BoxDecoration(
    color: Colors.purpleAccent,
    shape: BoxShape.circle,
  ),
  width: 150,
  height: 150,
)

边界

image.png

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),
    ),
  ),
)

阴影

image.png

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,我们会得到一个更好的结果。让我们看看!

image.png

双色线性梯度

image.png

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的值。

image.png

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]

image.png

在下面的例子中,我们可以看到一个美丽的线性梯度充满屏幕。

image.png

Center(
  child: Container(
    decoration: BoxDecoration(
      gradient: LinearGradient(
        begin: Alignment.bottomLeft,
        end: Alignment.topRight,
        colors: [
          Color(0xFFFBA3660),
          Color(0xFF1C256E),
        ],
        stops: [0.3, 0.75],
      ),
    ),
  ),
)

组合容器

组合容器是将一个容器设置在另一个容器内,或者换句话说,将一个容器设置为另一个容器的孩子。

子部件有一个高度和宽度

image.png

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,
  ),
)

青色容器已经被声明为紫色容器的一个孩子。

子部件被对齐到父部件的底部中心(父部件的对齐属性)。

子小组件有高度但没有宽度

image.png

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,
  ),
)

我们已经设置了孩子的高度,但没有设置孩子的宽度。然而,子部件(青色)完全覆盖了父部件的宽度

如果容器部件没有孩子,没有 _高度_,没有 _宽度_,没有 约束,也没有 对齐,但是父对象提供了有边界的约束,那么 容器 扩展以适应父对象提供的约束。

考虑到这一点,我们可以更好地解释前面截图中的青色小部件的行为。

  • 青色的部件没有孩子,也没有宽度**,而父方,紫色的容器,提供了有边界的约束。我们的子青色容器填补了父体的水平尺寸,因为它没有宽度。

这个子部件没有高度和宽度。

image.png

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)。

image.png

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的边距。

image.png

NOTE: Transform widget和transform container-property 将在接下来的故事中介绍。请不要错过它们!

如果你觉得这篇文章很有趣,或者它在某种程度上帮助了你,请给我很多👏.谢谢你阅读我的文章!

www.deepl.com 翻译