FlexLayout 为高度优化的 Yoga flexbox 实现(iOS/Android/...)添加了优雅的 Swift 接口。简洁、直观且可链式编写的语法。
Flexbox 相对于 UIStackView 有巨大的改进。它更易于使用,功能更强大,并且性能令人惊叹。
Yoga 是一个支持多平台 CSS Flexbox 的实现(iOS/Android/...)。Yoga 也是 React Native 的布局引擎。
需求
- iOS 8.0+
- Xcode 8.0+/ Xcode 9.0+
- Swift 3.0+/ Swift 4.0
内容
FlexLayout + PinLayout
FlexLayout 是 PinLayout 的伴侣。它们具有相似的语法和方法名。PinLayout 是一个受到 CSS 绝对定位极大启发的布局框架,它特别适用于更精细的控件和动画。它通过一次排放一个视图来实现完全控制(编码和调试简单)。
- 视图可以使用 FlexLayout、PinLayout 或两者同时进行布局!
- PinLayout 可以布局任何内容,但在需要布局许多视图而不需要 PinLayout 的最精细控制或复杂动画的情况下,FlexLayout 是最佳选择。
- 使用 PinLayout 布局的视图可以嵌入到 FlexLayout 的容器中,反之亦然。您可以选择最适合您情况的最佳布局框架。
FlexLayout 简介示例
示例 1
此示例将使用列和行弹性容器布局多个视图。
使用弹性容器的两个步骤
- 配置容器:初始化您的弹性盒子结构。注意,您稍后也可以更改它。
- 布局容器:容器的布局应从
layoutSubviews()
(或willTransition(to: UITraitCollection, ...)
和viewWillTransition(to: CGSize, ...)
)中进行。- 首先,您必须布局弹性容器,即定位它并可选地设置其大小。
- 然后,使用 Flex 方法
layout()
布局弹性容器子视图。
fileprivate let rootFlexContainer = UIView()
init() {
super.init(frame: .zero)
addSubview(rootFlexContainer)
...
// Column container
rootFlexContainer.flex.direction(.column).padding(12).define { (flex) in
// Row container
flex.addItem().direction(.row).define { (flex) in
flex.addItem(imageView).width(100).aspectRatio(of: imageView)
// Column container
flex.addItem().direction(.column).paddingLeft(12).grow(1).define { (flex) in
flex.addItem(segmentedControl).marginBottom(12).grow(1)
flex.addItem(label)
}
}
flex.addItem().height(1).marginTop(12).backgroundColor(.lightGray)
flex.addItem(bottomLabel).marginTop(12)
}
}
override func layoutSubviews() {
super.layoutSubviews()
// 1) Layout the flex container. This example use PinLayout for that purpose, but it could be done
// also by setting the rootFlexContainer's frame:
// rootFlexContainer.frame = CGRect(x: 0, y: 0,
// width: frame.width, height: rootFlexContainer.height)
rootFlexContainer.pin.top().left().width(100%).marginTop(topLayoutGuide)
// 2) Then let the flexbox container layout itself. Here the container's height will be adjusted automatically.
rootFlexContainer.flex.layout(mode: .adjustHeight)
}
示例 2
此示例使用 FlexLayout 实现了 Ray Wenderlich 的 Yoga 教程 屏幕界面。
init() {
...
rootFlexContainer.flex.define { (flex) in
// Image
flex.addItem(episodeImageView).grow(1).backgroundColor(.gray)
// Summary row
flex.addItem().direction(.row).padding(padding).define { (flex) in
flex.addItem(summaryPopularityLabel).grow(1)
flex.addItem().direction(.row).justifyContent(.spaceBetween).grow(2).define { (flex) in
flex.addItem(yearLabel)
flex.addItem(ratingLabel)
flex.addItem(lengthLabel)
}
flex.addItem().width(100).height(1).grow(1)
}
// Title row
flex.addItem().direction(.row).padding(padding).define { (flex) in
flex.addItem(episodeIdLabel)
flex.addItem(episodeTitleLabel).marginLeft(20)
}
// Description section
flex.addItem().paddingHorizontal(paddingHorizontal).define { (flex) in
flex.addItem(descriptionLabel)
flex.addItem(castLabel)
flex.addItem(creatorsLabel)
}
// Action row
flex.addItem().direction(.row).padding(padding).define { (flex) in
flex.addItem(addActionView)
flex.addItem(shareActionView)
}
// Tabs row
flex.addItem().direction(.row).padding(padding).define { (flex) in
flex.addItem(episodesTabView)
flex.addItem(moreTabView)
}
// Shows TableView
flex.addItem(showsTableView).grow(1)
}
}
override func layoutSubviews() {
super.layoutSubviews()
// 1) Layout the contentView & rootFlexContainer using PinLayout
contentView.pin.top().bottom().left().right()
rootFlexContainer.pin.top().left().right()
// 2) Let the flexbox container layout itself and adjust the height
rootFlexContainer.flex.layout(mode: .adjustHeight)
// 3) Adjust the scrollview contentSize
contentView.contentSize = rootFlexContainer.frame.size
}
FlexLayout 原则与哲学
- Flexbox 布局简单、强大且高效。
- FlexLayout 语法简洁且链式操作。
- FlexLayout/yoga 的速度惊人,甚至比手动布局还要快。见 性能。
- 源代码结构与 Flexbox 结构匹配,易于理解和修改。Flex 容器定义一行,其项(子项)是相互嵌套的。这使得 Flexbox 结构更加直观且易于理解。
- 支持从左到右(LTR)和从右到左(RTL)的语言。
注意:FlexLayout 包含 facebook/yoga 实现,并暴露了所有功能。因此,请注意,在本文档中我们将提到 FlexLayout,但这也适用于 Yoga。
FlexLayout 性能
使用 布局框架基准测试 来衡量 FlexLayout 的性能。FlexLayout 和 PinLayout 已添加到此基准,以比较它们的性能。
如下图表所示,FlexLayout 和 PinLayout 的性能比手动布局更快或相等。FlexLayout 和 PinLayout 比 UIStackViews 快 8x 到 12x,适用于所有类型的 iPhone(5S/6/6S/7/8/X)。
从 CSS 弹性盒子中的变异
-
在许多 CSS 方法属性名称中,增加了关键字
flex
以控制名称冲突。FlexLayout 为了更简洁,删除了此不必要的关键字。FlexLayout 名称 CSS 名称 React Native 名称 方向
flex-direction
flexDirection
换行
flex-wrap
flexWrap
增长
flex-grow
flexGrow
收缩
flex-shrink
flexShrink
基准值
flex-basis
flexBasis
开始对齐
flex-start
flexStart
结束对齐
flex-end
flexEnd
-
FlexLayout 默认属性与 CSS 弹性盒略有不同,以下表格总结了这些差异
属性 FlexLayout 默认值 CSS 默认值 React Native 默认值 方向
列 行 列 justifyContent
开始对齐 开始对齐 开始对齐 alignItems
拉伸 拉伸 拉伸 alignSelf
自动 自动 自动 alignContent
开始对齐 拉伸 开始对齐 增长
0 0 0 收缩
0 1 0 基准值
0 自动 0 换行
不换行 nowrap 不换行 -
FlexLayout 增加的功能:
- addItem()
- define()
- layout()
- isIncludedInLayout()
- markDirty()
- intrinsicSize
- sizeThatFits()
注意: FlexLayout 不支持 flexbox 的 order
属性。顺序由 flex 容器的 UIView.subviews
数组确定。
文档
flexbox 非常容易使用,且直观。flexbox 的定义特性是能够调整其项目、宽度、高度,以填充任何显示设备的可用空间。flex 容器扩展其项目以填充可用空闲空间,或缩小它们以防止溢出。
flex 布局由称为 flex 容器 的父容器及其直接子项(称为 flex 项目)组成。一个 flex 项目也可以是 flex 容器,即可以将其他 flex 项目添加到它。
轴
当与StackViews一起使用时,您需要从两个轴的角度思考——主轴和交叉轴。主轴由StackView的direction
属性定义,交叉轴垂直于主轴。
StackView方向 | 轴 |
---|---|
列(默认) | ![]() |
行 | ![]() |
部分
在下面的部分中,我们将看到
- 如何创建、修改和定义弹性容器和项。
- 弹性容器属性
- 弹性项属性
1. 创建、修改和定义弹性项
addItem(:UIView)
- 适用范围:
弹性容器
- 返回:新添加的弹性项的FlexLayout接口。
方法
addItem(_: UIView) -> Flex
此方法将弹性项(UIView)添加到弹性容器中。内部此方法将UIView作为子视图添加并启用弹性框。
使用示例
view.flex.addItem(imageView).width(100).aspectRatio(1)
addItem()
- 适用范围:
弹性容器
- 返回值:新创建的弹性项的FlexLayout接口。
方法
addItem() -> Flex
此方法类似于addItem(: UIView)
,但除此之外,它还会创建弹性项的UIView。内部方法创建了UIView,将其作为子视图添加并启用flexbox。当您不需要稍后引用时,此方法可以轻松添加弹性项/容器。
使用示例
view.flex.addItem().direction(.row).padding(10)
define()
- 适用范围:
弹性容器
- 参数:类型为
(flex: Flex) -> Void
的闭包。
方法
define(_ closure: (_ flex: Flex) -> Void)
此方法用于结构化代码以匹配flexbox结构。方法有一个闭包参数,名为flex
。该参数实际上是视图的flex接口。它可以用来添加其他弹性项和容器。
使用示例
view.flex.addItem().define { (flex) in
flex.addItem(imageView).grow(1)
flex.addItem().direction(.row).define { (flex) in
flex.addItem(titleLabel).grow(1)
flex.addItem(priceLabel)
}
}
也可以不使用 define()
方法得到相同的结果,但结果并不那么优雅。
let columnContainer = UIView()
columnContainer.flex.addItem(imageView).grow(1)
view.flex.addItem(columnContainer)
let rowContainer = UIView()
rowContainer.flex.direction(.row)
rowContainer.flex.addItem(titleLabel).grow(1)
rowContainer.flex.addItem(priceLabel)
columnContainer.flex.addItem(rowContainer)
define()
的优点:
- 源代码结构与flexbox结构相对应,使其更容易理解和修改。
- 更改弹性项的顺序,只需移动定义它的行/块上下即可。
- 将弹性项从一个容器移动到另一个容器,只需移动定义它的行/块即可。
- 结构看起来更类似于 HTML 和 React Native 的定义。
- 在
define
的闭包内,你可以做任何你想填充 flexbox 容器的事情。你可以使用for
循环,迭代数据数组,调用函数等...
访问 flex 项的 UIView
可以使用 flex.view
来访问 flex 项的 UIView。这在使用 flex.define()
方法时特别有用。
示例
这个示例创建了一个 flexbox 容器,并将其透明度设置为 0.8。
view.flex.direction(.row).padding(20).alignItems(.center).define { (flex) in
flex.addItem().width(50).height(50).define { (flex) in
flex.view?.alpha = 0.8
}
}
另一种可能的解决方案
view.flex.direction(.row).padding(20).alignItems(.center).define { (flex) in
let container = UIView()
container.alpha = 0.8
flex.addItem(container).width(50).height(50)
}
layout()
- 适用范围:
弹性容器
- 值:
fitContainer
/adjustWidth
/adjustHeight
- 默认值:
fitContainer
方法
-
layout(mode: LayoutMode = . fitContainer)
这个方法将布局 flex 容器的子项。布局模式
fitContainer
:这是一个默认模式,当未指定参数时使用。子项布局在容器的尺寸内(宽度和高度)。adjustHeight
:在这个模式下,子项仅使用容器的宽度进行布局。容器的长度将调整以适应 flexbox 的子项。adjustWidth
:在这个模式下,子项仅使用容器的高度进行布局。容器的宽度将调整以适应 flexbox 的子项。
使用示例
rootFlexContainer.flex.layout(mode: .adjustHeight)
2. Flexbox 容器属性
本节描述了所有 Flex 容器的属性。
direction()
- 适用范围:
弹性容器
- 值:
column
/columnReverse
/row
/rowReverse
- 默认值:
column
- CSS 名称:
flex-direction
属性
direction: 方向?
方法
-
direction(_: Direction)
direction
属性确定了主轴,从而定义了 flex 项在 flex 容器中的放置方向。direction
属性指定了 flex 项在 flex 容器中的布局方式,通过设置 flex 容器主轴的方向。它们可以按两种主要方向进行布局,例如垂直的列或水平的行。请注意,row 和 row-reverse 受 flex 容器布局方向(参阅
layoutDirection
属性)的影响。如果它的文本方向是 LTR(从左到右),row 代表从左到右的横轴,row-reverse 代表从右到左;如果方向是 rtl,则相反。
值 | 结果 | 描述 |
---|---|---|
列(默认) | ![]() |
从上到下 |
columnReverse | ![]() |
从下到上 |
行 | ![]() |
与文本方向相同 |
rowReverse | ![]() |
与文本方向相反 |
使用示例
view.flex.direction(.column) // Not required, default value.
view.flex.direction(.row)
示例 1
本例展示了如何将三个按钮居中,按钮之间间隔为 10 像素。
示例源代码
rootFlexContainer.flex.justifyContent(.center).padding(10).define { (flex) in
flex.addItem(button1)
flex.addItem(button2).marginTop(10)
flex.addItem(button3).marginTop(10)
}
justifyContent()
- 适用范围:
弹性容器
- 取值:
start
/end
/center
/spaceBetween
/spaceAround
/spaceEvenly
- 默认值:
start
- CSS 名称:
justify-content
方法
justifyContent(_: JustifyContent)
justifyContent
属性定义了弹性容器当前行的主轴对齐方式。当一行上的所有弹性项目都达到其最大尺寸时,它有助于分配剩余的额外空间。例如,如果子项目是垂直流动的,那么justifyContent
控制它们如何在垂直方向上对齐。
用法示例
view.flex.justifyContent(.start) // default value.
view.flex.justifyContent(.center)
alignItems()
- 适用范围:
弹性容器
- 值:
stretch
/start
/end
/center
/baseline
- 默认值:
stretch
- CSS名称:
align-items
方法
alignItems(_: AlignItems)
alignItems
属性定义了在当前行上沿着交叉轴如何排列灵活项。类似于justifyContent
,但对于交叉轴(垂直于主轴而言)。例如,如果子项是垂直流动的,则alignItems
控制它们如何进行水平对齐。
direction(.column) | direction(.row) | |
---|---|---|
stretch(默认值) | ![]() |
![]() |
开始对齐 | ![]() |
![]() |
结束对齐 | ![]() |
![]() |
center | ![]() |
![]() |
alignSelf()
- 适用范围:
弹性容器
- 值:
auto
/stretch
/start
/end
/center
/baseline
- 默认值:
auto
- CSS名称:
align-self
方法
alignSelf(_: AlignSelf)
alignSelf
属性控制子项在交叉方向上的对齐,覆盖父项的alignItems
。例如,如果子项是垂直流动的,则alignSelf
将控制灵活项如何水平对齐。
auto
值表示使用灵活容器的alignItems
属性。有关其他值的说明,请参见alignItems
。
wrap()
- 适用范围:
弹性容器
- 值:
noWrap
/wrap
/wrapReverse
- 默认值:
noWrap
- CSS名称:
flex-wrap
方法
wrap(_: Wrap)
wrap
属性控制灵活容器是单行还是多行,以及交叉轴的方向,这决定了新行堆叠的方向。
默认情况下,灵活容器将所有灵活项放入一行。使用此属性我们可以更改这一点。我们可以告诉容器将项目排列成一行或多行,以及新行堆叠的方向
备注:交叉轴是与主轴垂直的轴。其方向取决于主轴方向。
使用示例
view.flex.wrap(.nowrap) // Not required, default value.
view.flex.wrap(.wrap)
alignContent()
- 适用范围:
弹性容器
- 值:
start
/end
/center
/stretch
/spaceBetween
/spaceAround
- 默认值:
start
- CSS 名称:
align-content
方法
alignContent(_: AlignContent)
alignContent 属性在交叉轴有多余空间时,会沿着交叉轴方向对 flex 容器中的弹性项进行排列,类似于 justifyContent 属性如何沿着主轴方向对单个弹性项进行排列。
注意,当 flex 容器只有一行时,alignContent 属性没有效果。
direction(.column) | direction(.row) | |
---|---|---|
start(默认) | ![]() |
![]() |
结束对齐 | ![]() |
![]() |
center | ![]() |
![]() |
拉伸 | ![]() |
![]() |
spaceBetween | ![]() |
![]() |
spaceAround | ![]() |
![]() |
layoutDirection()
FlexLayout 支持从左到右 (LTR) 和从右到左 (RTL) 的语言。
使用 start
或 end
属性,您可以在不考虑项目是否将显示在屏幕的左边或右边(根据用户的语言)的情况下定位视图。
方法
-
layoutDirection(_: LayoutDirection)
layoutDirection 属性控制 flex 容器的布局方向。值
.inherit
Inherit 在所有节点上默认为继承,除了根节点,它默认为 LTR。您需要自己检测用户首选的方向(大多数平台都有一种标准的方法来做这件事)并在您的布局树根上设置此方向。.ltr
: 从左到右布局视图。(默认值).rtl
: 从右到左布局视图。
3. Flexbox子项属性
本节描述了所有弹性子项的属性。
grow
- 适用范围:
flex 项目
- 默认值:0
- CSS 名称:
flex-grow
方法
-
grow(_: CGFloat)
grow
属性定义了Flex项目在必要时扩展的能力。它接受一个无单位的值,用作比例。它决定了项目应该占用Flex容器内部多少的可用空间。增长值为0(默认值)将保持视图在主轴方向上的大小。如果您希望视图使用可用空间,请设置增长值 > 0。
例如,如果所有项目都设置 grow
为1,那么每个子项将在容器内部设置为相同的大小。如果您将其中一个子项的值设为2,那么该子项将占用其他子项的两倍空间。
shrink
- 适用范围:
flex 项目
- 默认值:0
- CSS 名称:
flex-shrink
方法
-
shrink(_: CGFloat)
它指定了 "Flex 缩放因子",该因子决定了在主轴空间不足时,Flex项目相对于Flex容器中其他Flex项目的缩放程度。省略时,将其设置为0,并乘以Flex
basis
以分配负空间。缩放值为0保持视图在主轴方向上的大小。请注意,这可能会导致视图溢出其Flex容器。
缩放是关于比例的。如果一个项目的缩放值为3,而其他项目的缩放值为1,则该项目将比其他项目更快地缩小3倍。
basis
- 适用范围:
flex 项目
- 默认值:0
- CSS 名称:
flex-basis
方法
-
basis(_ : CGFloat?)
此属性具有与宽度和高度属性相同的值,并指定了Flex项目的初始大小,在根据增长和缩减因子分配自由空间之前。指定
nil
将基础设置为auto
,这意味着长度等于项目的长度。如果项目未指定长度,长度将根据其内容确定。 -
基础(_ : FPercent)
此属性具有与宽度和高度属性相同的值,并指定了Flex项目的初始大小,在根据增长和缩减因子分配自由空间之前。
isIncludedInLayout()
- 适用范围:
flex 项目
方法
isIncludedInLayout(_ value: Bool)
该属性控制动态地决定一个 Flexbox 的 UIView 是否包含在 Flexbox 布局中。当 Flexbox 的 UIView 被排除时,FlexLayout 不会布局该视图及其子视图。
FlexLayout 在以下情况下会自动包含 UIView:
- 第一次访问
UIView.flex
属性时 - 当使用
addItem(:UIView)
或addItem()
将子视图添加到 Flexbox 容器时
display
- 适用范围:
flex 项目
方法
display(_: Display)
设置项目的显示或隐藏,使用 none
值时,项目将被隐藏且不包括在布局中。
markDirty()
- 适用范围:
flex 项目
方法
-
markDirty()
该框架高度优化,只有当 Flex 属性更改或 Flex 容器大小更改时才布局 Flex Item。如果您想强制 FlexLayout 布局 Flex Item,可以使用markDirty()
标记它。脏标志会传播到 Flexbox 树的根,确保当任何项被无效化时,其整个子树将被重新计算。
使用示例
在更新UILabel的文本时,需要将该标签标记为脏,并重新布局弹性容器。
// 1) Update UILabel's text
label.text = "I love FlexLayout"
// 2) Mark the UILabel as dirty
label.flex.markDirty()
// 3) Then force a relayout of the flex container.
rootFlexContainer.flex.layout()
OR
setNeedsLayout()
sizeThatFits()
- 适用范围:
flex 项目
方法
sizeThatFits()
返回在指定帧尺寸布局时的项目大小。
使用示例
获取布局在宽度为200像素的容器中的视图大小。
let layoutSize = viewA.flex.sizeThatFits(size: CGSize(width: 200, height: CGFloat.greatestFiniteMagnitude))
intrinsicSize
- 适用范围:
flex 项目
属性
intrinsicSize
项目自然大小,仅考虑视图本身的属性。独立于项目框架。
4. 绝对定位
- 适用范围:
flex 项目
- 参数:CGFloat
方法
位置(_: 位置)
位置属性告诉flexbox你希望项目在父元素中的位置。位置值相对(默认)
absolute
:使用属性定位视图:top()、bottom()、left()、right()、start()、end()。
用法示例
view.flex.position(.absolute).top(10).left(10).size(50)
top(), bottom(), left(), right(), start(), end(), vertically(), horizontally(), all()
将 position
属性设置为 .absolute
的弹性项目相对于其父元素进行绝对定位。这是通过以下方法实现的
方法
top(: CGFloat)
/top(: FPercent)
控制子项顶部边缘与父项顶部边缘的距离。bottom(: CGFloat)
/bottom(: FPercent)
控制子项底部边缘与父项底部边缘的距离。left(: CGFloat)
/left(: FPercent)
控制子项左侧边缘与父项左侧边缘的距离。right(: CGFloat)
/right(: FPercent)
控制子项右侧边缘与父项右侧边缘的距离。start(: CGFloat)
/start(: FPercent)
控制子项起始边缘与父项起始边缘的距离。在从左到右的方向(LTR)中,它对应于left()
属性,在 RTL 中对应于right()
属性。end(: CGFloat)
/end(: FPercent)
控制子项结束边缘与父项结束边缘的距离。在从左到右的方向(LTR)中,它对应于right()
属性,在 RTL 中对应于left()
属性。vertically(: CGFloat)
/vertically(: FPercent)
控制子项顶部和底部边缘与父项边缘的距离。等于top().bottom()
。horizontally(: CGFloat)
/horizontally(: FPercent)
控制子项左侧和右侧边缘与父项边缘的距离。等于left().right()
。all(: CGFloat)
/all(: FPercent)
控制子项边缘与父项边缘的距离。等于top().bottom().left().right()
。
使用这些属性可以控制绝对定位项在其父元素内的尺寸和位置。因为绝对定位的子项不会影响其同级元素的布局。绝对定位可以用于创建叠加层并在 Z 轴上堆叠子项。
使用示例
view.flex.position(.absolute).top(10).right(10).width(100).height(50)
view.flex.position(.absolute).left(20%).right(20%)
5. 调整大小
宽度和高度以及大小
FlexLayout提供方法来设置视图的宽度和高度。
方法
width(_ width: CGFloat?)
该值指定视图的宽度(以像素为单位)。该值必须为非负数。调用width(nil)
以重置属性。width(_ percent: FPercent)
该值指定视口宽度百分比的宽度。该值必须为非负数。调用width(nil)
以重置属性。height(_ height: CGFloat?)
该值指定视图的高度(以像素为单位)。该值必须为非负数。调用height(nil)
以重置属性。height(_ percent: FPercent)
该值指定视图高度占容器高度百分比的值。该值必须为非负数。调用height(nil)
以重置属性。size(_ size: CGSize?)
该值指定视图的宽度和高度(以像素为单位)。值必须为非负数。调用size(nil)
以重置属性。size(_ sideLength: CGFloat?)
该值指定视图的宽度和高度(以像素为单位),创建一个正方形视图。值必须为非负数。调用size(nil)
以重置属性。
使用示例
view.flex.width(100)
view.flex.width(50%)
view.flex.height(200)
view.flex.size(250)
minWidth(), maxWidth(), minHeight(), maxHeight()
FlexLayout 提供了设置视图最小和最大宽度以及最小和最大高度的方法。
使用 minWidth, minHeight, maxWidth 和 maxHeight 可以提供对布局中项目最终尺寸的更多控制。通过将这些属性与 grow、shrink 和 alignItems(.stretch) 混合使用,可以使项具有动态尺寸,并在您控制的范围内。
Max 属性有用的一个例子是当您使用 alignItems(.stretch),但您知道当项目增加到某个点之后看起来可能不好看。在这种情况下,该项目将扩展到其父级的尺寸或直到它达到 Max 属性中指定的尺寸。
类似地,当使用 shrink 时,Min 属性也适用。例如,您可能希望容器的小部件在一行中缩放到合适的位置,但如果您指定了最小宽度,则它们将在一定点后换行(如果使用 wrap(.wrap))。
Min 和 Max 维度约束在使用 aspectRatio 时的另一个用例。
方法
minWidth(_ width: CGFloat?)
该值指定视图的最小宽度(以像素为单位)。该值必须是正数。调用 minWidth(nil) 重置属性。minWidth(_ percent: FPercent)
该值指定视图的最小宽度为容器宽度的百分比。该值必须是正数。调用 minWidth(nil) 重置属性。maxWidth(_ width: CGFloat?)
该值指定视图的最大宽度(以像素为单位)。该值必须是正数。调用 maxWidth(nil) 重置属性。maxWidth(_ percent: FPercent)
该值指定视图的最大宽度为容器宽度的百分比。该值必须是正数。调用 maxWidth(nil) 重置属性。minHeight(_ height: CGFloat?)
该值指定视图的最小高度(以像素为单位)。该值必须是正数。调用 minHeight(nil) 重置属性。minHeight(_ percent: FPercent)
该值指定视图的最小高度为容器高度的百分比。该值必须是正数。调用 minHeight(nil) 重置属性。maxHeight(_ height: CGFloat?)
该值指定了视图中视图的最大高度(以像素为单位)。该值必须是非负数。调用maxHeight(nil)
以重置属性。maxHeight(_ percent: FPercent)
该值指定了视图的最大高度为其容器高度的百分比。该值必须是非负数。调用maxHeight(nil)
以重置属性。
使用示例
view.flex.maxWidth(200)
view.flex.maxWidth(50%)
view.flex.width(of: view1).maxWidth(250)
view.flex.maxHeight(100)
view.flex.height(of: view1).maxHeight(30%)
aspectRatio()
AspectRatio是Yoga引人的属性,在CSS中不存在。AspectRatio解决了一个维度的元素和宽高比问题,这在图像、视频和其他媒体类型中很常见。AspectRatio接受任何大于0的浮点数,默认值是未定义。
- AspectRatio被定义为节点宽度和高度的比率,例如,如果节点宽高比为2,则其宽度是其高度的两倍。
- AspectRatio尊重项的Min和Max维度。
- AspectRatio的优先级高于
grow
。 - 如果AspectRatio、宽度、高度都被设置,则交叉维度将被覆盖。
- 调用
aspectRatio(nil)
以重置属性。
使用示例
imageView.flex.aspectRatio(16/9)
6. 外边距
通过将外边距应用于项,您指定了该项的边缘与其最近的同级或父边框之间的偏移。
方法
marginTop(_ value: CGFloat)
,marginTop(_ percent: FPercent)
上边距指定元素顶部边框与最近的兄弟元素(项目)或父元素(容器)的距离偏移量。marginLeft(_ value: CGFloat)
,marginLeft(_ percent: FPercent)
左边距指定元素左边边框与最近的兄弟元素(项目)或父元素(容器)的距离偏移量。marginBottom(_ value: CGFloat)
,marginBottom(_ percent: FPercent)
下边距指定元素底部边框与最近的兄弟元素(项目)或父元素(容器)的距离偏移量。marginRight(_ value: CGFloat)
,marginRight(_ percent: FPercent)
右边距指定元素右边边框与最近的兄弟元素(项目)或父元素(容器)的距离偏移量。marginStart(_ value: CGFloat)
,marginStart(_ percent: FPercent)
设置起始边距。在从左到右direction中,起始边距指定左边距。在从右到左direction中,起始边距指定右边距。marginEnd(_ value: CGFloat)
,marginEnd(_ percent: FPercent)
设置结束边距。在从左到右direction中,结束边距指定右边距。在从右到左direction中,结束边距指定左边距。marginHorizontal(_ value: CGFloat)
,marginHorizontal(_ percent: FPercent)
将左、右、起始和结束边距设置为特定值。marginVertical(_ value: CGFloat)
,marginVertical(_ percent: FPercent)
将上下边距设置为特定值。margin(_ insets: UIEdgeInsets)
使用UIEdgeInsets设置所有边距。此方法特别适用于使用iOS 11UIView.safeAreaInsets
设置所有边距。margin(_ insets: NSDirectionalEdgeInsets)
使用NSDirectionalEdgeInsets设置所有边距。此方法在布局支持从右到左/从左到右语言的视图时非常有用。margin(_ value: CGFloat)
将所有边距设置为特定值。margin(_ vertical: CGFloat, _ horizontal: CGFloat)
margin(_ top: CGFloat, _ horizontal: CGFloat, _ bottom: CGFloat)
margin(_ top: CGFloat, _ left: CGFloat, _ bottom: CGFloat, _ right: CGFloat)
用法示例
view.flex.margin(20)
view.flex.marginTop(20%).marginLeft(20%)
view.flex.marginHorizontal(20)
view.flex.margin(safeAreaInsets)
view.flex.margin(10, 12, 0, 12)
7. 填充
填充指定子元素与容器某一边的距离。
方法
paddingTop(_ value: CGFloat)
,paddingTop(_ percent: FPercent)
paddingLeft(_ value: CGFloat)
,paddingLeft(_ percent: FPercent)
paddingBottom(_ value: CGFloat)
,paddingBottom(_ percent: FPercent)
paddingRight(_ value: CGFloat)
,paddingRight(_ percent: FPercent)
paddingStart(_ value: CGFloat)
,paddingStart(_ percent: FPercent)
paddingEnd(_ value: CGFloat)
,paddingEnd(_ percent: FPercent)
paddingHorizontal(_ value: CGFloat)
,paddingHorizontal(_ percent: FPercent)
paddingVertical(_ value: CGFloat)
,paddingVertical(_ percent: FPercent)
padding(_ insets: UIEdgeInsets)
使用 UIEdgeInsets 设置所有内边距。此方法尤其适用于使用 iOS 11UIView.safeAreaInsets
设置所有内边距。padding(_ insets: NSDirectionalEdgeInsets)
使用 NSDirectionalEdgeInsets 设置所有内边距。此方法尤其适用于在支持RTL/LTR语言的视图中布局时使用 iOS 11UIView.directionalLayoutMargins
设置所有内边距。padding(_ value: CGFloat)
,padding(_ percent: FPercent)
padding(_ vertical: CGFloat, _ horizontal: CGFloat)
,padding(_ vertical: FPercent, horizontal: FPercent)
padding(_ top: CGFloat, _ horizontal: CGFloat, _ bottom: CGFloat)
,padding(_ top: FPercent, _ horizontal: FPercent, _ bottom: FPercent)
padding(_ top: CGFloat, _ left: FPercent, _ bottom: FPercent, _ right: FPercent)
,padding(_ top: FPercent, _ left: FPercent, _ bottom: FPercent, _ right: FPercent)
使用示例
view.flex.padding(20)
view.flex.paddingTop(20%).paddingLeft(20%)
view.flex.paddingBottom(20)
view.flex.paddingHorizontal(20)
view.flex.padding(10, 12, 0, 12)
9. 额外的 UIView 方法
FlexLayout 还添加了设置常用 UIView 属性的方法。
方法
backgroundColor(_ color: UIColor)
设置弹性项的 UIView 背景颜色。cornerRadius(_ value: CGFloat)
设置弹性项的 UIView 圆角半径。border(_ width: CGFloat, _ color: UIColor)
设置弹性项的 UIView 边框。
使用示例
// Create a gray column container and add a black horizontal line separator
flex.addItem().backgroundColor(.gray).define { (flex) in
flex.addItem().height(1).backgroundColor(.black)
}
// Set rounded corner
flex.addItem().cornerRadius(12)
// Set border
flex.addItem().border(1, .black)
FlexLayout API 文档
示例应用
FlexLayout 的示例应用展示了 FlexLayout 的一些使用示例。
请参阅示例应用部分以获取更多信息.
常见问题解答
- 问题: Flex 项溢出或比其容器更大吗?
答案: 默认情况下,Flex 项的shrink
值为 0,这保持了项在主轴方向上的当前大小。这可能会导致项溢出其 Flex 容器。要修复此问题,只需指定一个大于 0 的shrink
值。
view.flex.shrink(1)
-
问题:如何保持视图大小(宽度/高度)?
答案: 默认情况下,视图的 flex shrink 值设置为 1,这会在视图在主轴方向上大于其 Flex 容器时减小视图的大小。如果是列方向,则调整高度;如果是行方向,则调整宽度。将此值设置为 0 将保持视图在主轴方向上的大小。 -
问题:如何将 CGFloat、Float 或 Int 值的百分比应用到视图上?
回复: FlexLayout 的一些方法有一个类型为FPercent
的参数。您只需简单地将%
运算符添加到您的值中,就可以指定此类参数(例如:view.flex.width(25%)
。如果您有一个类型为 CGFloat、Float 或 Int 的值,只需添加%
运算符即可。let percentageValue: CGFloat = 50 view.flex.height(percentageValue%)
Flexbox 扩展外部链接
- 使用 Yoga 介绍 Flexbox
- CSS Flexbox 参考指南:Flexbox 完全指南
- Raywenderlich 有趣的 Yoga 教程
- CSS Flexbox 简介
- Flex 快捷参考:使用 CSS 测试 Flexbox 属性
- Mozialla:使用 CSS 的 Flexbox 实现高级布局
贡献、评论、想法、建议、问题、...
对于任何 评论、想法、建议,请简单打开一个问题。
对于 问题,请查看Yoga 的问题。您的问题可能已经被报告。如果没有,这可能是一个 FlexLayout 问题。在这种情况下,打开一个问题,我们会告诉您问题是否与 Yoga 的实现相关。
如果您认为 FlexLayout 很有趣,感谢您通过 Star 支持。您将能够轻松地稍后检索它。
如果您愿意贡献,欢迎您加入!
安装
CocoaPods
要使用 CocoaPods 将 FlexLayout 集成到您的 Xcode 项目中,请在您的 Podfile
中指定它。
pod 'FlexLayout'
然后,运行 pod install
。
Carthage
使用 Carthage 将 FlexLayout 集成到 Xcode 项目中
- 在你的
Cartfile
中指定
github "layoutBox/FlexLayout"
- 运行
carthage update
来构建框架。 - 在 Xcode 项目中“嵌入式二进制”部分添加构建后的
FlexLayout.framework
。
Swift 包管理器
其他 Swift 包
要将 FlexLayout 集成到其他 Swift 包中,添加它作为依赖项
.package(url: "https://github.com/layoutBox/FlexLayout.git", from: "1.3.18")
在 Xcode 目标中
- 要将 FlexLayout 集成到 Xcode 目标中,使用“文件 -> Swift 包 -> 添加包依赖”菜单项。
- 将 "FLEXLAYOUT_SWIFT_PACKAGE=1" 添加到 Xcode 目标的
GCC_PREPROCESSOR_DEFINITIONS
编译设置中。(目标 -> 编译设置 -> Apple Clang-Preprocessing -> 宏选项)
更新记录
FlexLayout近期历史记录在更改日志中进行了文档记录。
许可证
MIT许可证