大家好,我是微浅笑的蜗牛,。

上一篇文章咱们讲了款式树的生成,供认了每个节点的款式。这一节首要介绍怎样生成布局树,也便是供认每个节点的方位。

盒子模型

首要介绍一下盒子模型,由于布局都是以它为基础来打开。

简略来说,一个节点Swift的方位区域由内容区、内边距、边框、外边距四个部分组成,如下图所示。

传闻你想写个烘托引擎 - 布局树

盒子类型

元素设定的 display 类型,选择了盒子类型。常用的有如下几种阅读器怎样检查前史阅读记载

  • block,块级元素,生成块级盒子
  • inline,行内元素,生成行内级盒子
  • none,swifter标明该元素不闪现

block box

块盒子,它是一个容器。默许竖向摆放,内部元素独占一行。如下所示:

传闻你想写个烘托引擎 - 布局树

inline box

行内盒子,它也是一个容器。默许横向摆放,在一行内展现。当一行布满后,会折行闪现。如下图所示:

传闻你想写个烘托引擎 - 布局树

anonymous box

匿名盒子比较特别,它不与实践的元素相关,所以称为appreciate匿名。关超神兽宠店于匿名盒子的介绍可点击数据结构知识点总结文末链接 1 检查。

由于盒子容器中只能包括一种类型的盒子,swift怎样读要么是 block,要么是 inappleline。当盒子中混合了不同布局类型的元素时,会产生匿名盒子。

匿名盒子又分为匿名块盒子和swift体系匿名行内盒子。

1. 匿名块盒子

匿名块盒子的产生分为两种状况。

当 blo阅读器前史上的痕迹在哪里ck box 包括 block 和 inline阅读器怎样检查前史阅读记载 元素时,会产生一个匿名块盒子,将 inliappreciatene 元素包裹在其间。

举个比方:

div, p {applicationdisswift怎样读play: block}
<div>Some inline text <p>followed by a paragraph</p> followed by more inline text.</div>

div 和 p 都是块级元素,前后的文字是行内元素。此刻会产生两个匿名块盒子阅读器的前史记载在哪,别离包长沙师范学院裹前后的文字。如下图所示:

传闻你想写个烘托引擎 - 布局树

相同,当在 inline box 中包括了 block 元素时,也会产生匿名块陈涉世家翻译及原文盒子。

阅读器怎样检查前史阅读记载如:

p    { display: inline }
span { display: bloc仓鼠饲养八大禁忌k }swift什么意思
<p>
This i长沙师范学院s anonymous text b阅读器前史记载设置efore the SPAN.
<span>This is the content of SPAN.</span&gappointmentt;
Thisswift银行 is anonymous text after the S阅读器前史上的痕迹在哪里PAN.
</p&数据结构难学吗gt;
  • p 生成行内盒子,span阅读器approach成块级盒子。此刻,行内盒子包括块级盒子。
  • "This iappearances anonyappearancemous text数据结构c语言版第二版课后答案 before the SPAN." 会产生匿名application块盒子崇圣寺三塔
  • "This iapples anonymous text after the SPAN." 也会产生匿名块盒子。

如下图所示:

传闻你想写个烘托引擎 - 布局树

2. 匿名行内盒子

一种比较常见的状况,当 block box 中包括文字时,会主动生成匿名行内盒子包裹文字。

比方:

p    { display: block }
<p>Some <em>emphasized</em> text</p>

<p> 生成了块盒子,<em> 生成了行数据结构知识点总结内盒子。这时会生成匿名行内盒子,别离包裹 Some 和 text。如下图所示:

传闻你想写个烘托引擎 - 布局树

数据结构

盒子模型

上边提到过,盒子模型包括内容、内边距、边框、外边距几部分。内容区是一个矩形,其余部分属于边距类型,可别离设置上下左右的值。

关于内容区来说,界说矩形结构:

struct Rect {
var x: Float = 0.0
var y: Float = 0.0
var wid仓鼠寿命th: Float = 0.0
var height: Float = 0.0
}

关于边距类型,界说如下:

// 边距界说
struct EdgeSizes {
var left: Float = 0.appstore0
var right: Float = 0.0
var top: Float = 0.0
var bottom: Floa阅读器拜访过于频繁不能用t = 0.0
}

那么盒子模型的界说如下:

struct Dimensions {
// 内容区
var content:阅读器的阅读前史怎样删去 Rect = Rect()
// 内边距
var padding: EdgeSizes = EdgeSizes()
// 外边距
var marg数据结构教程第5版李春葆答案in: EdgeSizes = EdgeSizes()
/swift什么意思/ 边框
var border: EdgeSizes = EdgeSizes()
}

接着来界说布局类型,枚举即可,相关各自的款式节点。

// 布局类型
enum BoxType {
case A崇圣寺三塔nonymousBlock
case BlockNode(StyleNode)
case InlineNode(Style长沙市气候Node)
}

布局树

布局树appear节点包括盒子模型数据、布局类型、子节点。界说如下:

// 布局树
class LayoutBox {
// 布局描绘
var dimensions: Dimensions
// 类型
var boxType: Boapprovex数据结构严蔚敏Type
// 子节点布局
var children: [LayoutBox]
}

布局

元素的布局类型由 display 特征选择,swift什么意思可从节点的款式表中得到。

这儿咱们只结束 block 节点的布局,inline 的暂且不处理。block 类型的节点会生成块级盒子,纵向摆放。

那么布局究竟是要做些什么呢?其实首要是供认各个节点盒子模型中的数据,比方宽高、边距等等。

关于宽高的处理,有一些前置知识很重要。

节点的宽度是由父节点宽度来选择的,阅读器的前史记载在哪是由上至下的处理。超神兽宠店而高度却不相同,父节点swift什么意思的高度由子节点的高度之和选择。它是一个由下至上的进程,有必要等全部子节数据结构与算法点高度核算出来后,父节点长沙市气候的高度才能供认。

整个布局进程,咱们将分为 4 个进程来处理:

  • 宽度核算。核算节点宽度,供认水平方向距离。
  • 方位核算。核算节点坐标,供认竖直方向距离。
  • 子节点布局。供认子节点布局信息,一起更新父节点高度。
  • 高度核算。获取 css 设置的高度。

宽度核算

宽度核算是最为杂乱的一环。由于这跟 width、padding、border、margin 的设定有关,其间最重要的是 width 和 margin。

别的,width、margin 能够设置为 auto,标明让阅读器自行核算它们的approve值。

  • 当 width 为 auto 时,标明假若在有边距的状况下,尽或许的将自身宽度设置为父容器的宽度。
  • 当 margin 为 auto 时,标明阅读器挑选一个适宜的边距。

假定咱们将 「width + margiAPPn + padding + border 之和」界说为元素所占的总宽度。如下图所示:

传闻你想写个烘托引擎 - 布局树

而总宽度和实践父容器的宽度很或许存在不swiftly匹配的状况,要么溢出,要么短少。这时候就需求依据 width、margin 各自的设置来进行调整,以满意需求。

下面,就来讲讲不同appreciate状况下的调整。

1. 首要做一些前置工作,进行数据预备。如下:

  • 从款式表中提取宽度,若 width 没有设置,默许值为 auto
  • 从款式表中提取水平边距数据结构严蔚敏,margin、padding、border 的CSS left 和 right 值。swift银行
  • 核算总宽度,totalWidth = 全部边距 + 宽度。
  • 核算剩下空间,leftSpace = 父容器宽度 – 总宽度。

2.appstore据 css 中的核算方法(概况可点击文末链接陈思思 2),可分为如下几种现象:

  • 当 width 不为 auto,且总宽度 > 父容器宽度,将 maswift什么意思rgin-left/margin-r数据结构c语言版第二版课后答案ight 中为 auto 的值设置为 0。

    假设 margin-left 为 auto,那么 margin-left = 0;

    假设 margin-right 为 auto,那么 margin-righappstoret = 0;

    传闻你想写个烘托引擎 - 布局树

  • 当 width/margin-left/margin-right 都有设置值时(也便是都不为 auto),依据 block 的 direction 调整 margin。

    假设是 ltr,则调整 margin-right;假设是 rtl,则数据结构知识点总结调整 margin-left。

    这儿咱们默许都是 ltr,只调整 margin-right,批改其值满意宽度要求。

    传闻你想写个烘托引擎 - 布局树

  • 当 width 不为 auto,margin-left/marg数据结构与算法in-right 仅且只需一个为 auto 时,将其间为 auswift什么意思to 的特征设置为剩下空间。

    传闻你想写个烘托引擎 - 布局树

  • 当 width 为 auto,将 mar阅读器前史记载设置gin-left/margin-rig数据结构教程第5版李春葆答案ht 中为 aut阅读器前史记载删了怎样找回o 的特征设置为 0,width 设置为剩下空间。

    传闻你想写个烘托引擎 - 布局树

  • 当 width 不为 auto,margin-left 和 margin-超崇高骑士right 都为 auto,两者平分剩下空间。

    传闻你想写个烘托引擎 - 布局树

详细的代码处理,可检查 Layout.swift 中 calculateBlockWidth 函数。

3. 在处理完app装置下载以上几种状况后,margin、width 的值现已供认,此刻能够更新盒子模型数据appear,首要是水平方向的数据。

方位核算

这一步首要是核算坐标点,以及笔直方向的距离。

笔直方向的距离,别离approach取出 border仓鼠寿命、margin、padding 的 top 和 bottom 值即可。

节点的坐标,跟父容器的方位有关。如下图所示:

传闻你想写个烘托引擎 - 布局树

上图赤色虚线框为子节点 2 的区域,现在咱们要供认子节点 2 的坐标。

关于 x 坐标来说,比较好了解。

子节点的 x = 父容器 x + margin + border + padding

y 坐标的核算如下:

子节点的 y = 父容器 y + 父容器高度 + margin + bor阅读器下载der + padding

这儿或许有些让人威胁,为什么是加上父容器的高度?

block 是纵向摆放,不应该是核算出该节点之前的全部子节点所占空间吗?

是的,没错。其实这儿父容器的高度便是现已布局结束的子节点高度之和,下面的子节点布局中会提到。

子节点布局

这一步遍历子节点,递归核算子节点的布局。

// 核算子节点布局
func layoutBlockChildren() {
for child in self.children {app装置下载
child.layout(containingBlock: self.dimensions)
// 核算整体高度
self.dimensions.content.height += child.d仓鼠寿命imensions.marginBox().height
}
}

留心这儿父节点高度的核算,此刻会累加子节点的高度。每当布局结束一个节点,就加上它的高度。因而,父节点的高度是布局好的子节点高度之和。

高度

若节点自身设置了高度,则取其值。

// 假设设置了 height,则取该值
func calculateBlockHeight() {
if let styleNode = getStyleNode() {
// 获取设置的 height
iappearancef let heightValue = styleNode.getValue(name: "height") {
if case Value.Length(let height, .Px) = heightValue {
self.dimensions.content.height = height
}
}
}
}

生成布局树

遍历款式树,依据元素的布局类阅读器的阅读前史怎样删去型,生成布局树节点,进而阅读器前史记载删了怎样找回生成布局树。

// 递归承阅读器认每个节点的 display 数据
mutating func buildLayoutBox(styleNode: StyleNode) -> LayoutBox {
let root = LayoutBox(styleNode: styleNode)appreciate
for child in styleNode.children {
s阅读器的阅读前史怎样删去witch chilswift体系d.getDisplay() {
capprovease .Block:
let childLayoutBox = buildLayoutBapp装置下载ox(styleNode: child)
rooswift什么意思t.cappstorehildren.append(childLayoutBox)
breakapple
case .Inline:
let childLayoutBox = buildLayout阅读器前史记载设置Box(styleNode: child)
// inline 元素,找到 container
let container = root.getInlineContainer()
container.children.append(childLayoutBox)
break
d长沙师范学院efault:
break
}
}
return root
}approach

上边的代码别离处理了 bloapproachck 和 in数据结构line 元素的状况。这儿需求留心,关于 inline 的处理,跟匿名盒子有关。

当 block box 中包括了 inlswift什么意思ine 元素时,会创立匿名块长沙市气候盒子包approve裹 inline 元素。摆放在一起的 inline 元素,会放在同一个APP匿名盒子中。

如下图所示:

传闻你想写个烘托引擎 - 布局树

假设 block 的毕竟一个节点现已是匿名盒子,那么直接运用;否则创立一个新的盒子刺进。

// 获取 inline 节点的容器。假设数据结构知识点总结 block 包括一个 inline 节点,它会创立一个匿名 block 来包裹该 in阅读器前史记载设置line
// 全部swift什么意思在 block 中的摆放在一起的 inline 节点,简略处理,都会放在一个匿名 block 中。
func getInlineContainer() -> LayoutBox {
switch self.boxType {
case .AnonymousBlock, .InliappstoreneNode(_):
return self
caapproachse .BlockNode(_):
// 取出毕竟一个子节点
let lastChild = self.children.last
// 假设现已是匿名盒子,不做处理,稍后回来
if case .AnonymousBlock = lastChild?.boxType  {
} else {
// 生成新的匿名swift怎样读盒子
leswift结算体系t anonymousBlock = LayoutBox(boxType: .AnonymousBlock)
// 添加匿名匿名盒子
self.children.appe超神兽宠店nd(anonymousBlock)
}application
// 回来毕竟子节点
return self.children.last!
}
}

毕竟对布局树进行布局,供认节点方位信息。

无缺代码可检查:github.com/silswift代码是什么意思an-liu/t…

总结

这一节首要介绍了关于怎样供认节点的布局信息,并生成了一颗布局树。其间最为杂乱的是宽度的核算,处理状况有点多。

下一节将叙述CSS怎样进行制造,将布局信息转化为像素点,敬请期待~

毕竟

您要是觉得文章有帮忙的话,能够点击下方手刺重视大众号「微浅笑的蜗牛」。

在大众号谈天框中回复「蜗牛」,可添加微信进行沟通~

参考资料

  • www.w3.org/TR/CSS21/vi…
  • www.w3.org/TR/CSS2/vis…
  • limpet.net/mbrubeck/20…