CGLayout
一个强大的自动布局框架,可以管理 UIView(NSView)、CALayer 和未渲染的视图。具有跨层级坐标系。采用基于矩形约束的执行。快速、异步、声明式、可缓存、可扩展。支持 iOS、macOS、tvOS、Linux。
由 [LayoutBenchmarkFramework](https://github.com/lucdion/LayoutFrameworkBenchmark) 执行快速教程
使用 CGLayout
和布局块构建布局。要组合块到单一单元,请使用 LayoutScheme
实体(或其他后缀为 Scheme
的实体)。
let subviewsScheme = LayoutScheme(blocks: [
// ... layout blocks
])
要定义 "视图" 元素的块,请使用 LayoutBlock
实体,或直接使用便利获取方法 func layoutBlock(with:constraints:)
。
titleLabel.layoutBlock(
with: Layout(x: .center(), y: .top(5), width: .scaled(1), height: .fixed(120)),
constraints: [
logoImageView.layoutConstraint(for: [.bottom(.limit(on: .inner))])
]
)
/// or using anchors
titleLabel.layoutBlock(
with: Layout(x: .center(), y: .top(5), width: .scaled(1), height: .fixed(120)),
constraints: { anchors in
anchors.top.equal(to: logoImageView.layoutAnchors.bottom)
}
)
为了理解如何构建布局块,让我们看看在 LayoutBlock
中的布局过程。例如,我们有这个配置
LayoutBlock(
with: layoutElement,
layout: Layout(x: .left(10), y: .top(10), width: .boxed(10), height: .boxed(10)),
constraints: [
element1.layoutConstraint(for: [
.bottom(.limit(on: .outer)), .right(.limit(on: .inner))
]),
element2.layoutConstraint(for: [
.right(.limit(on: .outer)), .bottom(.limit(on: .inner))
])
]
)
布局锚点是限制器,它们面向框架属性(例如侧面、大小、位置)。任何基于侧面的锚点有三种基本实现:对齐、限制(裁剪)、拉动。这些实现中的每一个都依赖于工作空间:内部和外部。基于大小的锚点由两种实现表示:大小、内边距。您可以在 enum LayoutAnchor
中找到所有布局锚点。
要创建关联的布局约束,请使用 protocol LayoutConstraintProtocol
。框架提供了这样的默认实现
LayoutConstraint
:简单关联约束,该约束使用传递的元素的var frame
来约束源矩形。使用它可以建立对外部工作空间的依赖。AdjustLayoutConstraint
:关联约束以调整源空间的尺寸。只有符合protocol AdjustableLayoutElement
的元素才能使用它。ContentLayoutConstraint
:使用内部边界进行约束的关联约束,定义在protocol LayoutElement
的'layoutBounds'属性中。如果你需要创建对内部工作空间的依赖,请使用它。例如,UIScrollView
内的元素。BaselineLayoutConstraint
:依赖于基准线的关联约束。只有符合protocol TextPresentedElement
的元素才能使用它。AnonymConstraint
:独立于外部环境限制源空间的约束。MutableLayoutConstraint
:创建可更改活动状态的布局约束。您可以通过相关元素的便利函数找到所有这些约束。用它来构建布局块。
在常见情况下,应在其他所有约束之后(但不总是如此)应用调整约束。
weatherLabel.layoutBlock(
with: Layout(x: .left(10), y: .top(), width: .scaled(1), height: .scaled(1)),
constraints: [
weatherImageView.layoutConstraint(for: [.top(.limit(.inner)), .right(.limit(.outer)), .height()]),
weatherLabel.adjustLayoutConstraint(for: [.width()])
]
)
AnonymConstraint(anchors: [
Inset(UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 15))
])
为了实现自定义布局实体并保存强类型代码,请使用static func build(_ base: Conformed) -> Self
方法。
每个布局块都有布局、截屏和应用截屏的方法。因此,您可以使用布局块进行直接布局、背景布局和缓存布局。
// layout directly
layoutScheme.layout()
// layout in background
let bounds = view.bounds
DispatchQueue.global(qos: .background).async {
let snapshot = self.layoutScheme.snapshot(for: bounds)
DispatchQueue.main.sync {
self.layoutScheme.apply(snapshot: snapshot)
}
}
// cached layout
if UIDevice.current.orientation.isPortrait, let snapshot = portraitSnapshot {
layoutScheme.apply(snapshot: snapshot)
} else if UIDevice.current.orientation.isLandscape, let snapshot = landscapeSnapshot {
layoutScheme.apply(snapshot: snapshot)
} else {
layoutScheme.layout()
}
典型的sizeThatFits(_:)
方法实现。
func sizeThatFits(_ size: CGSize) -> CGSize {
let sourceRect = CGRect(origin: .zero, size: size)
let snapshot = scheme.snapshot(for: sourceRect)
return snapshot.frame
}
LayoutGuide
框架提供了LayoutGuide
,作为UILayoutGuide
的类似物。它可以生成视图并将它们添加到层次结构中。LayoutGuide
可以用作不可见的限制器,也可以用作布局容器。默认布局容器:StackLayoutGuide
- 简单的堆叠实现。ScrollLayoutGuide
- 与UIScrollView
具有类似接口。通过使用它,我们可以在任何地方启用滚动。LayoutPlaceholder
- 单个元素容器,可以懒惰地加载视图。针对CALayer
- LayerPlaceholder
和UIView
- ViewPlaceholder
有默认实现。UIViewPlaceholder
- 基于UILayoutGuide
的单个元素容器。
UILayoutGuide
也采用了LayoutElement
协议。因此,你可以安全地基于UIView.safeAreaLayoutGuide
和其他内容创建约束。
RTL
要启用从右到左的模式,请使用全局配置。
CGLConfiguration.default.isRTLMode = true
有关更多详细信息,请参阅文档和示例项目。
代码文档
请参阅这里
示例
macOS, iOS, tvOS
要运行示例项目,请先克隆存储库,然后从 Example 目录中运行 pod install
.
Linux
要运行示例项目,请先克隆存储库,然后从 linux_example
目录中运行 swift run
.
需求
Swift 5
安装
CGLayout 通过 CocoaPods 提供。要安装它,只需将以下行添加到您的 Podfile 中
pod "CGLayout"
贡献
我非常欢迎您的反馈、建议和 pull 请求。更多信息请参阅 这里
作者
Denis Koryttsev 邮箱:[email protected] Twitter:[https://twitter.com/K_o_D_e_N](https://twitter.com/K_o_D_e_N)
许可
CGLayout 在MIT许可下可用。有关更多信息,请参阅LICENSE文件。