FlexLayout 2.0.10

FlexLayout 2.0.10

测试已测试
Lang语言 SwiftSwift
许可 MIT
发布最近发布2024年6月
SPM支持 SPM

Luc DionLuc Dion 维护。



FlexLayout 2.0.10

  • Luc Dion

FlexLayout


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 正在积极更新。因此,请经常访问以查看最新更改。您还可以 Star 它,以方便稍后检索。


FlexLayout + PinLayout

FlexLayout

FlexLayoutPinLayout 的伴侣。它们具有相似的语法和方法名。PinLayout 是一个受到 CSS 绝对定位极大启发的布局框架,它特别适用于更精细的控件和动画。它通过一次排放一个视图来实现完全控制(编码和调试简单)。

  • 视图可以使用 FlexLayout、PinLayout 或两者同时进行布局!
  • PinLayout 可以布局任何内容,但在需要布局许多视图而不需要 PinLayout 的最精细控制或复杂动画的情况下,FlexLayout 是最佳选择。
  • 使用 PinLayout 布局的视图可以嵌入到 FlexLayout 的容器中,反之亦然。您可以选择最适合您情况的最佳布局框架。

FlexLayout 简介示例

示例 1

此示例将使用列和行弹性容器布局多个视图。

使用弹性容器的两个步骤

  1. 配置容器:初始化您的弹性盒子结构。注意,您稍后也可以更改它。
  2. 布局容器:容器的布局应从 layoutSubviews()(或 willTransition(to: UITraitCollection, ...)viewWillTransition(to: CGSize, ...))中进行。
    1. 首先,您必须布局弹性容器,即定位它并可选地设置其大小。
    2. 然后,使用 Flex 方法 layout() 布局弹性容器子视图。

FlexLayout example

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
}

📌此示例在 Examples App 中可用。请参阅完整的 源代码


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. 如何创建、修改和定义弹性容器和项。
  2. 弹性容器属性
  3. 弹性项属性

📌本文档是使用FlexLayout的指南。您还可以查看FlexLayout的API文档


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 控制它们如何在垂直方向上对齐。
direction(.column) direction(.row)
start(默认) 项目在主轴的起始端堆叠。
结束对齐 项目在主轴的末端堆叠。
center 项目沿主轴居中对齐。
spaceBetween 项目在主轴上平均分布;第一个项目位于起始端,最后一个项目位于末端。
spaceAround 项目在主轴上平均分布,周围有相等的空间。
spaceEvenly 项目在主轴上平均分布,周围有相等的空间。
用法示例
  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属性控制灵活容器是单行还是多行,以及交叉轴的方向,这决定了新行堆叠的方向。

默认情况下,灵活容器将所有灵活项放入一行。使用此属性我们可以更改这一点。我们可以告诉容器将项目排列成一行或多行,以及新行堆叠的方向

备注:交叉轴是与主轴垂直的轴。其方向取决于主轴方向。

direction(.column) direction(.row) 描述
noWrap(默认值) 单行可能会造成容器溢出。新增:灵活项显示为一行,默认情况下它们会被压缩以适应灵活容器的宽度
换行 多行,方向由direction()定义。新增:如果需要,灵活项将显示为多行,从左到右,从上到下排列
wrapReverse 多行,与由direction()定义的方向相反。新增:如果需要,灵活项将显示为多行,从左到右,从下到上排列
使用示例
  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) 的语言。

使用 startend 属性,您可以在不考虑项目是否将显示在屏幕的左边或右边(根据用户的语言)的情况下定位视图。

方法

  • layoutDirection(_: LayoutDirection)
    layoutDirection 属性控制 flex 容器的布局方向。

    • .inherit
      Inherit 在所有节点上默认为继承,除了根节点,它默认为 LTR。您需要自己检测用户首选的方向(大多数平台都有一种标准的方法来做这件事)并在您的布局树根上设置此方向。
    • .ltr: 从左到右布局视图。(默认值)
    • .rtl: 从右到左布局视图。

3. Flexbox子项属性

本节描述了所有弹性子项的属性。

📌记得Flex容器本身也是Flex项目,因此所有这些属性也适用于容器。

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

📌请参阅示例应用中的“Yoga C”示例。源代码


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 11 UIView.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 11 UIView.safeAreaInsets 设置所有内边距。
  • padding(_ insets: NSDirectionalEdgeInsets)
    使用 NSDirectionalEdgeInsets 设置所有内边距。此方法尤其适用于在支持RTL/LTR语言的视图中布局时使用 iOS 11 UIView.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 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 的问题。您的问题可能已经被报告。如果没有,这可能是一个 FlexLayout 问题。在这种情况下,打开一个问题,我们会告诉您问题是否与 Yoga 的实现相关。

如果您认为 FlexLayout 很有趣,感谢您通过 Star 支持。您将能够轻松地稍后检索它。

如果您愿意贡献,欢迎您加入!


安装

CocoaPods

要使用 CocoaPods 将 FlexLayout 集成到您的 Xcode 项目中,请在您的 Podfile 中指定它。

  pod 'FlexLayout'

然后,运行 pod install

Carthage

使用 Carthage 将 FlexLayout 集成到 Xcode 项目中

  1. 在你的 Cartfile 中指定
github "layoutBox/FlexLayout"
  1. 运行 carthage update 来构建框架。
  2. 在 Xcode 项目中“嵌入式二进制”部分添加构建后的 FlexLayout.framework

Swift 包管理器

其他 Swift 包

要将 FlexLayout 集成到其他 Swift 包中,添加它作为依赖项

.package(url: "https://github.com/layoutBox/FlexLayout.git", from: "1.3.18")

在 Xcode 目标中

  1. 要将 FlexLayout 集成到 Xcode 目标中,使用“文件 -> Swift 包 -> 添加包依赖”菜单项。
  2. 将 "FLEXLAYOUT_SWIFT_PACKAGE=1" 添加到 Xcode 目标的 GCC_PREPROCESSOR_DEFINITIONS 编译设置中。(目标 -> 编译设置 -> Apple Clang-Preprocessing -> 宏选项)

更新记录

FlexLayout近期历史记录在更改日志中进行了文档记录。


许可证

MIT许可证