本文原作者: Xinlei (译),原文发布于微信公众号: Flutter社区 

https://mp.weixin.qq.com/s/2GFKxfAtnOozLsUiRUQPHg

前言

本文最初来自于社区成员 Marcelo Glasberg 在 Medium 发表的文章——"初学者应知应会的 Flutter 高级布局规则 (Flutter: The Advanced Layout Rule Even Beginners Must Know)",然后被 Flutter Team 发现并收录到 Flutter 官方文档,后经中文社区成员翻译发布至 Flutter 中文文档网站,如果您对本文有任何建议和讨论,请到 GitHub Issue 中反馈。

译者注: 在认真阅读完这篇文章后,我认为它对 Flutter 开发者来说具有相当大的指导意义,每一位 Flutter 开发都应该认真理解其中的布局约束过程,是非常必要的。因此,在翻译本文的过程中,我们对译文反复打磨,尽可能保留原文想传递给读者的内容,希望让每一位看到此文的开发者都能够有所收获。

深入理解布局约束

我们会经常听到一些开发者在学习 Flutter 时的疑惑: 为什么我设置了width:100,但是看上去却不是 100 像素宽呢。(注意,本文中的 "像素" 均指的是逻辑像素) 通常你会回答,将这个 widget 放进Center中,对吧?

别这么干

如果你这样做了,他们会不断找你询问这样的问题: 为什么FittedBo又不起作用了?为什么Column又溢出边界,亦或是IntrinsicWidth应该做什么。

其实我们首先应该做的,是告诉他们 Flutter 的布局方式与 HTML 的布局差异相当大 (这些开发者很可能是 Web 开发者),然后要建议他们熟记这条规则:

  • 首先,上层 widget 向下层 widget 传递约束条件。

  • 然后,下层 widget 向上层 widget 传递大小信息。

  • 最后,上层 widget 决定下层 widget 的位置。

如果我们在开发时无法熟练运用这条规则,在布局时就不能完全理解其原理,所以越早掌握这条规则越好!

更多细节:

  • Widget 会通过它的父级获得自身的约束。约束实际上就是 4 个浮点类型的集合: 最大/最小宽度,以及最大/最小高度。

  • 然后,这个 widget 将会逐个遍历它的 children 列表。向子级传递约束 (子级之间的约束可能会有所不同),然后询问它的每一个子级需要用于布局的大小。

  • 然后,这个 widget 就会对它子级的 children 逐个进行布局 (水平方向是x轴,竖直是y轴)。

  • 最后,widget 将会把它的大小信息向上传递至父 widget (包括其原始约束条件)。

例如,如果一个 widget 中包含了一个具有 padding 的 Column,并且要对 Column 的子 widget 进行如下的布局:

那么谈判将会像这样:

布局大小协作讨论 (4)

Widget

嘿!我的父级:我的约束是多少?

@Parent

Parent

你的宽度必须在 80 到 300 像素之间,高度必须在 30 到 85 之间。

Widget

嗯...我想要 5 个像素的内边距,这样我的子级能最多拥有 290 个像素宽度和 75 个像素高度。

Widget

嘿,我的第一个子级,你的宽度必须要在 0 到 290,长度在 0 到 75 之间。

@First child

First child

OK,那我想要 290 像素的宽度,20 个像素的长度。

Widget

嗯...由于我想要将我的第二个子级放在第一个子级下面,所以我们仅剩 55 个像素的高度给第二个子级了。

Widget

嘿,我的第二个子级,你的宽度必须要在 0 到 290,长度在 0 到 55 之间。

@Second child

Second child

OK,那我想要 140 像素的宽度,30 个像素的长度。

Widget

很好。我的第一个子级将被放在 x: 5 & y: 5 的位置, 而我的第二个子级将在 x: 80 & y: 25 的位置。

Widget

嘿,我的父级,我决定我的大小为 300 像素宽度,60 像素高度。

@Parent

限制

正如上述所介绍的布局规则中所说的那样,Flutter 的布局引擎有一些重要限制:

  • 一个 widget 仅在其父级给其约束的情况下才能决定自身的大小。这意味着 widget 通常情况下不能任意获得其想要的大小

  • 一个 widget 无法知道,也不需要决定其在屏幕中的位置。因为它的位置是由其父级决定的。

  • 当轮到父级决定其大小和位置的时候,同样的也取决于它自身的父级。所以,在不考虑整棵树的情况下,几乎不可能精确定义任何 widget 的大小和位置。

样例

以下的效果图片和样例代码均可通过下面这个 DartPad 链接查看: dartpad.cn/759e9e061a6d4c247700429ddda09b8b

也可以在这个 GitHub 仓库中获得: github.com/marcglasberg/flutter_layout_article

以下将依次介绍这些示例:

样例 1

Container(color: Colors.red)

整个屏幕作为 Container的父级,并且强制 Container变成和屏幕一样的大小。

所以这个 Container 充满了整个屏幕,并绘制成红色。

样例 2

Container(width: 100, height: 100, color: Colors.red)

红色的 Container想要变成 100 x 100 的大小,但是它无法变成,因为屏幕强制它变成和屏幕一样的大小。

所以 Container充满了整个屏幕。

样例 3

Center(child: Container(width: 100, height: 100, color: Colors.red)
)

屏幕强制 Center 变得和屏幕一样大,所以 Center 充满了屏幕。

然后 Center 告诉 Container 可以变成任意大小,但是不能超出屏幕。现在,Container 可以真正变成 100 × 100 大小了。

样例 4

Align(alignment: Alignment.bottomRight,child: Container(width: 100, height: 100, color: Colors.red),
)

与上一个样例不同的是,我们使用了 Align 而不是 Center

Align 同样也告诉 Container,你可以变成任意大小。但是,如果还留有空白空间的话,它不会居中 Container。相反,它将会在允许的空间内,把 Container 放在右下角 (bottomRight)。

样例 5

Center(child: Container(color: Colors.red,width: double.infinity,height: double.infinity,)
)

屏幕强制 Center 变得和屏幕一样大,所以 Center 充满屏幕。

然后 Center 告诉 Container 可以变成任意大小,但是不能超出屏幕。现在,Container 想要无限的大小,但是由于它不能比屏幕更大, 所以就仅充满屏幕。

样例 6

Center(child: Container(color: Colors.red))

屏幕强制 Center 变得和屏幕一样大,所以 Center 充满屏幕。

然后 Center 告诉Container 可以变成任意大小,但是不能超出屏幕。由于 Container 没有子级而且没有固定大小,所以它决定能有多大就有多大, 所以它充满了整个屏幕。

但是,为什么 Container 做出了这个决定?非常简单,因为这个决定是由 Container widget 的创建者决定的。可能会因创造者而异,而且你还得阅读Container 文档来理解不同场景下它的行为。

样例 7

Center(child: Container(color: Colors.red,child: Container(color: Colors.green, width: 30, height: 30),)
)

屏幕强制 Center 变得和屏幕一样大,所以 Center 充满屏幕。

然后 Center 告诉红色的 Container 可以变成任意大小,但是不能超出屏幕。由于 Container 没有固定大小但是有子级,所以它决定变成它 child 的大小。

然后红色的 Container 告诉它的 child 可以变成任意大小,但是不能超出屏幕。

而它的 child 是一个想要 30 × 30 大小绿色的 Container。由于红色的 Container和其子级一样大,所以也变为 30 × 30。由于绿色的 Container 完全覆盖了红色 Container,所以你看不见它了。

样例 8

Center(child: Container(color: Colors.red,padding: const EdgeInsets.all(20.0),child: Container(color: Colors.green, width: 30, height: 30),)
)

红色 Container 变为其子级的大小,但是它将其 padding 带入了约束的计算中。所以它有一个 30 x 30 的外边距。由于这个外边距,所以现在你能看见红色了。而绿色的 Container 则还是和之前一样。

样例 9

ConstrainedBox(constraints: BoxConstraints(minWidth: 70, minHeight: 70,maxWidth: 150, maxHeight: 150,),child: Container(color: Colors.red, width: 10, height: 10),
)

你可能会猜想 Container 的尺寸会在 70 到 150 像素之间,但并不是这样。ConstrainedBox 仅对其从其父级接收到的约束下施加其他约束。

在这里,屏幕迫使 ConstrainedBox 与屏幕大小完全相同,因此它告诉其子 Widget 也以屏幕大小作为约束,从而忽略了其 constraints 参数带来的影响。

样例 10

Center(child: ConstrainedBox(constraints: BoxConstraints(minWidth: 70, minHeight: 70,maxWidth: 150, maxHeight: 150,),child: Container(color: Colors.red, width: 10, height: 10),)
)

现在,Center 允许 ConstrainedBox 达到屏幕可允许的任意大小。ConstrainedBoxconstraints 参数带来的约束附加到其子对象上。

Container 必须介于 70 到 150 像素之间。虽然它希望自己有 10 个像素大小,但最终获得了 70 个像素 (最小为 70)。

样例 11

Center(child: ConstrainedBox(constraints: BoxConstraints(minWidth: 70, minHeight: 70,maxWidth: 150, maxHeight: 150,),child: Container(color: Colors.red, width: 1000, height: 1000),)
)

现在,Center 允许 ConstrainedBox 达到屏幕可允许的任意大小。ConstrainedBoxconstraints 参数带来的约束附加到其子对象上。

Container 必须介于 70 到 150 像素之间。虽然它希望自己有 1,000 个像素大小, 但最终获得了 150 个像素 (最大为 150)。

样例 12

Center(child: ConstrainedBox(constraints: BoxConstraints(minWidth: 70, minHeight: 70,maxWidth: 150, maxHeight: 150,),child: Container(color: Colors.red, width: 100, height: 100),)
)

现在,Center 允许 ConstrainedBox 达到屏幕可允许的任意大小。ConstrainedBoxconstraints 参数带来的约束附加到其子对象上。

Container 必须介于 70 到 150 像素之间。虽然它希望自己有 100 个像素大小, 因为 100 介于 70 至 150 的范围内,所以最终获得了 100 个像素。

样例 13

UnconstrainedBox(child: Container(color: Colors.red, width: 20, height: 50),
)

屏幕强制 UnconstrainedBox 变得和屏幕一样大,而 UnconstrainedBox 允许其子级的 Container 可以变为任意大小。

样例 14

UnconstrainedBox(child: Container(color: Colors.red, width: 4000, height: 50),
)

屏幕强制 UnconstrainedBox 变得和屏幕一样大,而 UnconstrainedBox 允许其子级的 Container 可以变为任意大小。

不幸的是,在这种情况下,容器的宽度为 4,000 像素,这实在是太大,以至于无法容纳在 UnconstrainedBox 中,因此UnconstrainedBox 将显示溢出警告 (overflow warning)。

样例 15

OverflowBox(minWidth: 0.0,minHeight: 0.0,maxWidth: double.infinity,maxHeight: double.infinity,child: Container(color: Colors.red, width: 4000, height: 50),
);

屏幕强制OverflowBox 变得和屏幕一样大,并且OverflowBox 允许其子容器设置为任意大小。

OverflowBoxUnconstrainedBox 类似,但不同的是,如果其子级超出该空间,它将不会显示任何警告。

在这种情况下,容器的宽度为 4,000 像素,并且太大而无法容纳在 OverflowBox中,但是OverflowBox 会全部显示,而不会发出警告。

样例 16

UnconstrainedBox(child: Container(color: Colors.red, width: double.infinity, height: 100,)
)

这将不会渲染任何东西,而且你能在控制台看到错误信息。

UnconstrainedBox 让它的子级决定成为任何大小,但是其子级是一个具有无限大小的Container

Flutter 无法渲染无限大的东西,所以它抛出以下错误: BoxConstraints forces an infinite width. (盒子约束强制使用了无限的宽度)

样例 17

UnconstrainedBox(child: LimitedBox(maxWidth: 100,child: Container( color: Colors.red,width: double.infinity, height: 100,))
)

这次你就不会遇到报错了。UnconstrainedBoxLimitedBox 一个无限的大小;但它向其子级传递了最大为 100 的约束。

如果你将 UnconstrainedBox 替换为Center,则LimitedBox 将不再应用其限制 (因为其限制仅在获得无限约束时才适用),并且容器的宽度允许超过 100。

上面的样例解释了LimitedBoxConstrainedBox 之间的区别。

样例 18

FittedBox(child: Text('Some Example Text.'),
)

屏幕强制 FittedBox 变得和屏幕一样大,而 Text 则是有一个自然宽度 (也被称作 intrinsic 宽度),它取决于文本数量,字体大小等因素。

FittedBoxText 可以变为任意大小。但是在 Text 告诉 FittedBox 其大小后,FittedBox 缩放文本直到填满所有可用宽度。

样例 19

Center(child: FittedBox(child: Text('Some Example Text.'),)
)

但如果你将 FittedBox 放进 Center widget 中会发生什么?Center 将会让 FittedBox 能够变为任意大小,取决于屏幕大小。

FittedBox 然后会根据 Text 调整自己的大小,然后让 Text 可以变为所需的任意大小,由于二者具有同一大小,因此不会发生缩放。

样例 20

Center(child: FittedBox(child: Text('This is some very very very large text that is too big to fit a regular screen in a single line.'),)
)

然而,如果 FittedBox 位于Center 中,但 Text 太大而超出屏幕,会发生什么?

FittedBox 会尝试根据 Text 大小调整大小,但不能大于屏幕大小。然后假定屏幕大小,并调整 Text 的大小以使其也适合屏幕。

样例 21

Center(child: Text('This is some very very very large text that is too big to fit a regular screen in a single line.'),
)

然而,如果你删除了 FittedBoxText 则会从屏幕上获取其最大宽度,并在合适的地方换行。

样例 22

FittedBox(child: Container(height: 20.0, width: double.infinity,)
)

FittedBox 只能在有限制的宽高中对子 widget 进行缩放 (宽度和高度不会变得无限大)。否则,它将无法渲染任何内容,并且你会在控制台中看到错误。

样例 23

Row(children:[Container(color: Colors.red, child: Text('Hello!')),Container(color: Colors.green, child: Text('Goodbye!')),]
)

屏幕强制 Row 变得和屏幕一样大,所以 Row 充满屏幕。

UnconstrainedBox 一样,Row 也不会对其子代施加任何约束,而是让它们成为所需的任意大小。Row 然后将它们并排放置,任何多余的空间都将保持空白。

样例 24

Row(children:[Container(color: Colors.red, child: Text('This is a very long text that won’t fit the line.')),Container(color: Colors.green, child: Text('Goodbye!')),]
)

由于 Row 不会对其子级施加任何约束,因此它的 children 很有可能太大而超出 Row 的可用宽度。在这种情况下,Row 会和 UnconstrainedBox 一样显示溢出警告。

样例 25

Row(children:[Expanded(child: Container(color: Colors.red, child: Text('This is a very long text that won’t fit the line.'))),Container(color: Colors.green, child: Text('Goodbye!')),]
)

Row 的子级被包裹在了 Expanded widget 之后,Row 将不会再让其决定自身的宽度了。

取而代之的是,Row 会根据所有 Expanded 的子级 来计算其该有的宽度。

换句话说,一旦你使用Expanded,子级自身的宽度就变得无关紧要,直接会被忽略掉。

样例 26

Row(children:[Expanded(child: Container(color: Colors.red, child: Text(‘This is a very long text that won’t fit the line.’)),),Expanded(child: Container(color: Colors.green, child: Text(‘Goodbye!’),),]
)

如果所有 Row 的子级都被包裹了 Expanded widget,每一个 Expanded 大小都会与其 flex 因子成比例,并且 Expanded widget 将会强制其子级具有与 Expanded 相同的宽度。

换句话说,Expanded 忽略了其子 Widget 想要的宽度。

样例 27

Row(children:[Flexible(child: Container(color: Colors.red, child: Text('This is a very long text that won’t fit the line.'))),Flexible(child: Container(color: Colors.green, child: Text(‘Goodbye!’))),]
)

如果你使用 Flexible 而不是Expanded 的话, 唯一的区别是,Flexible会让其子级具有与Flexible相同或者更小的宽度。而 Expanded 将会强制其子级具有和Expanded 相同的宽度。但无论是 Expanded 还是 Flexible在它们决定子级大小时都会忽略其宽度。

这意味着,Row 要么使用子级的宽度,要么使用ExpandedFlexible 从而忽略子级的宽度。

样例 28

Scaffold(body: Container(color: blue,child: Column(children: [Text('Hello!'),Text('Goodbye!'),])))

屏幕强制 Scaffold 变得和屏幕一样大,所以 Scaffold 充满屏幕。然后 Scaffold 告诉 Container 可以变为任意大小,但不能超出屏幕。

当一个 widget 告诉其子级可以比自身更小的话,我们通常称这个 widget 对其子级使用 宽松约束 (loose)

样例 29

Scaffold(
body: SizedBox.expand(child: Container(color: blue,child: Column(children: [Text('Hello!'),Text('Goodbye!'),],))))

如果你想要 Scaffold 的子级变得和 Scaffold 本身一样大的话,你可以将这个子级外包裹一个SizedBox.expand

当一个 widget 告诉它的子级必须变成某个大小的时候,我们通常称这个 widget 对其子级使用 严格约束 (tight)

严格约束 (Tight) vs 宽松约束 (loose)

以后你经常会听到一些约束为严格约束或宽松约束,你花点时间来弄明白它们是值得的。

严格约束给你了一种获得确切大小的选择。换句话来说就是,它的最大/最小宽度是一致的,高度也一样。

如果你到 Flutter 的 box.dart 文件中搜索BoxConstraints 构造器,你会发现以下内容:

BoxConstraints.tight(Size size): minWidth = size.width,maxWidth = size.width,minHeight = size.height,maxHeight = size.height;

如果你重新阅读样例 2[1],它告诉我们屏幕强制 Container 变得和屏幕一样大。为何屏幕能够做到这一点,原因就是给 Container 传递了严格约束。

一个宽松约束换句话来说就是设置了最大宽度/高度,但是让允许其子 widget 获得比它更小的任意大小。换句话来说,宽松约束的最小宽度/高度为 0

BoxConstraints.loose(Size size): minWidth = 0.0,maxWidth = size.width,minHeight = 0.0,maxHeight = size.height;

如果你访问样例 3[2],它将会告诉我们 Center 让红色的 Container 变得更小,但是不能超出屏幕。Center 能够做到这一点的原因就在于 给 Container 的是一个宽松约束。总的来说,Center 起的作用就是从其父级 (屏幕) 那里获得的严格约束,为其子级 (Container)转换为宽松约束。

了解如何为特定 widget 制定布局规则

掌握通用布局是非常重要的,但这还不够。

应用一般规则时,每个 widget 都具有很大的自由度,所以没有办法只看 widget 的名称就知道可能它长什么样。

如果你尝试推测,可能就会猜错。除非你已阅读 widget 的文档或研究了其源代码,否则你无法确切知道 widget 的行为。

布局源代码通常很复杂,因此阅读文档是更好的选择。但是当你在研究布局源代码时,可以使用 IDE 的导航功能轻松找到它。

下面是一个例子:

  • 在你的代码中找到一个 Column 并跟进到它的源代码。为此,请在 (Android Studio/IntelliJ) 中使用command+B(macOS) 或 control+B (Windows/Linux)。你将跳到 basic.dart 文件中。由于Column 扩展了 Flex,请导航至 Flex 源代码 (也位于 basic.dart 中)。

  • 向下滚动直到找到一个名为createRenderObject() 的方法。如你所见,此方法返回一个RenderFlex。它是Column 的渲染对象,现在导航到 flex.dart 文件中的 RenderFlex 的源代码。

  • 向下滚动,直到找到 performLayout() 方法,由该方法执行列布局。

致谢

本文的顺利发布需感谢以下社区成员的支持: Xinlei Wang, Marcelo Glasberg, Simon Lightfoot, Luke, Alex, CaiJingLong, Yujie Ren, Kai Sun, Lynn Wang, Yisheng Xu,谢谢!

文中图片因排版效果使用圆角显示,实际效果无圆角,特此说明。如果您对本文有任何建议和讨论,请到 GitHub Issue 中反馈,因为外链限制,请到 flutter.cn 查看外部链接: flutter.cn/docs/development/ui/layout/constraints


长按右侧二维码

查看更多开发者精彩分享

"开发者说·DTalk" 面向中国开发者们征集 Google 移动应用 (apps & games) 相关的产品/技术内容。欢迎大家前来分享您对移动应用的行业洞察或见解、移动开发过程中的心得或新发现、以及应用出海的实战经验总结和相关产品的使用反馈等。我们由衷地希望可以给这些出众的中国开发者们提供更好展现自己、充分发挥自己特长的平台。我们将通过大家的技术内容着重选出优秀案例进行谷歌开发技术专家 (GDE) 的推荐。

 点击屏末 |  | 即刻报名参与 "开发者说·DTalk"


深入理解布局约束 | 开发者说·DTalk相关推荐

  1. 必读 | 深入理解 Flutter 的布局约束

    前言 本文最初来自于社区成员 Marcelo Glasberg 在 Medium 发表的文章--"初学者应知应会的 Flutter 高级布局规则 (Flutter: The Advanced ...

  2. 2022 年度作品优秀大赏 | 开发者说·DTalk

    岁聿云暮之际,回首 2022,开发者们一直在迈着坚定的步伐向顶峰攀登,我们也竭尽所能不断为大家提供帮助--操作系统 Android 13 完成 Beta 版到正式版的蜕变,开发工具 Flutter 3 ...

  3. 如何理解 Flutter 路由源码设计?| 开发者说·DTalk

    本文原作者: Nayuta,原文发布于: 进击的 Flutter   本期看点: 70 行代码实现一个丐版路由 路由源码细节解析 导语 某天在公众号看到这样一个问题 这问题我熟啊,刚好翻译 Overl ...

  4. 安居客 Android APP 走向平台化 | 开发者说·DTalk

    本文原作者: 张磊BARON,原文发布于微信公众号: BaronTalk  https://mp.weixin.qq.com/s/71VfmQ5ZyihgTwosMPbSmw 安居客 Android ...

  5. 不一样角度带您了解 Flutter 中的滑动列表实现 | 开发者说·DTalk

    本文原作者: 恋猫de小郭,原‍文发布于: GSYTech 本篇主要帮助剖析理解 Flutter 里的列表和滑动的组成,用比较通俗易懂的方式,从常见的 ListView 到 NestedScrollV ...

  6. 如何优化 Compose 的性能?通过「底层原理」寻找答案 | 开发者说·DTalk

    本文原作者: 朱涛,原文发布于: 朱涛的自习室‍ 今年的 Google I/O 大会上,Android 官方针对 Jetpack Compose 给出了一系列的性能优化建议,文档和视频都已经放出来了. ...

  7. WorkManager 流程分析和源码解析 | 开发者说·DTalk

    本文原作者: 狐友技术团队,原文发布于: 搜狐技术产品 https://mp.weixin.qq.com/s/KlzYHqd3RhF1D8dDAYiSjA 前言 WorkManager 统一了对于 A ...

  8. 字节跳动为什么选用 Flutter : 可能成为不一样的未来 | 开发者说·DTalk

    本文原作者: 袁辉辉,原文发布于微信公众号: Gityuan  https://mp.weixin.qq.com/s/SaIAQ22gbB4nJsDQj3QwrQ 2018 年 12 月,Google ...

  9. 拓展交流空间,分享开发精彩 | 开发者说·DTalk 鉴赏

    日月其迈,岁律更新,时间的洗礼让开发者们更加坚韧,持续探索,不断追求,同样也激励着我们为开发者提供更多的帮助与支持.不断迭代的技术产品是开发者们的趁手工具,定期更新的政策助力打造安全可靠的生态,透彻易 ...

最新文章

  1. 44、【华为HCIE-Storage】--InfoEqualizer
  2. 想拥有最新的微软嵌入式技术 就赶快加入微软嵌入式专家社区吧!
  3. WPF 路径动画PathAnimations的使用
  4. 2020-11-09
  5. 公众号回复单个图文消息
  6. 英特尔推出新CPU架构!3D封装打破摩尔定律限制,10nm芯片明年上市
  7. 线性表顺序存储的基本操作方法(C语言)
  8. bootstrap-自定义导航栏隐藏参数@screen-sm
  9. Android 资源(Resources)访问
  10. C++入门经典-例8.8-虚继承
  11. Windows11系统引导修复(因EasyBCD误删win11启动)
  12. 海康VisionMaster-脚本模块
  13. Win10 数字认证
  14. c语言url下载文件,C/C++轻松实现文件下载
  15. Timer 控件中的Elapsed事件与tick事件的区别
  16. mysql sql 按天分组统计_Mysql按日、周、月进行分组统计
  17. jmeter压力测试报告—模板
  18. 于Cd(Ⅲ)金属有机骨框架的新型造影剂Cd-MOF/Gd-DTPA/DMPE-DTPA-Gd-DMPE/
  19. RHCE7-NOTE(红帽工程师--题库详细笔记)
  20. LOL如何拯救小学生

热门文章

  1. SQL server不能修改表结构的解决办法
  2. 深入理解Pytorch负对数似然函数(torch.nn.NLLLoss)和交叉熵损失函数(torch.nn.CrossEntropyLoss)
  3. 解决Worker 1 failed executing transaction ‘ANONYMOUS‘ at master log mall-mysql-bin.000001, end_log_pos
  4. 蓝桥杯试题:Fibonacci数列
  5. iamp是什么意思计算机网络,IAMP是什么意思
  6. pop3 smtp iamp
  7. 2020-11-3(安卓开发入门)
  8. springmvc的工作原理
  9. Pygame 教程(2):重要的概念及对象
  10. 随鼠标滚轮缩小和放大图片