一个简单的类,用于方便地布局视图集合,同时利用 Auto Layout 的强大功能。
AloeStackView
是一个类,允许以垂直或水平列表形式布局视图集合。从广义上讲,它类似于 UITableView
,但其实现方式截然不同,并且它做出了不同的权衡。
AloeStackView
首先专注于使 UI 的实现非常快速、简单和直接。它通过以下两种方式实现这一点:
它利用 Auto Layout 的强大功能,在更改视图时自动更新 UI。
它放弃了 UITableView
的一些功能(例如视图回收),以便实现更简单、更安全的 API。
我们发现 AloeStackView
是一个有用的基础设施组件,希望您也觉得它有用!
允许您保持对视图的强引用并动态更改其属性,而 Auto Layout 会自动保持 UI 处于最新状态。
允许动态添加、移除、隐藏和显示视图,并可选择动画。
内置支持可自定义的视图间分隔符。
提供可扩展的 API,允许添加专门的功能,而无需修改 AloeStackView
本身。
在流量极高的 iOS 应用中得到广泛使用和验证。
小型、易于理解的代码库(少于 600 行代码),没有外部依赖项,使二进制文件大小的增加降至最低,并使代码贡献和调试变得轻松。
该仓库包含一个简单的 示例 iOS 应用。
您可以通过克隆仓库,打开 AloeStackViewExample.xcworkspace
并运行该应用来试用它。
示例应用展示了 AloeStackView
可以用于在 iOS 应用中实现屏幕的几种方式。
主要 API 通过 AloeStackView
类访问。
您可以在代码中非常轻松地创建 AloeStackView
的实例
import AloeStackView
let stackView = AloeStackView()
AloeStackView
是一个 UIView
(具体来说是一个 UIScrollView
),因此可以像应用中的任何其他视图一样使用。
或者,如果您想使用 AloeStackView
构建整个 UIViewController
,可以使用方便的 AloeStackViewController
类
import AloeStackView
public class MyViewController: AloeStackViewController {
public override func viewDidLoad() {
super.viewDidLoad()
stackView.addRow(...)
}
}
AloeStackViewController
与 UITableViewController
和 UICollectionViewController
等类非常相似,因为它为您创建和管理 AloeStackView
。您可以通过 stackView
属性访问 AloeStackView
。使用 AloeStackViewController
而不是在 UIViewController
中创建自己的 AloeStackView
只是为您节省了一些打字。
AloeStackView
的 API 通常处理“行”。行可以是您想在 UI 中使用的任何 UIView
。
默认情况下,行以垂直列排列,并且每行都拉伸 AloeStackView
的完整宽度。
可以使用 AloeStackView
上的 axis
属性来更改方向。当 axis
设置为 .horizontal
时,行彼此相邻排列(从左到右),并且 AloeStackView
水平滚动,每行都拉伸 AloeStackView
的完整高度。
要使用 AloeStackView
构建 UI,通常首先添加构成 UI 的行
for i in 1...3 {
let label = UILabel()
label.text = "Label \(i)"
stackView.addRow(label)
}
如果 AloeStackView
的长度增长到超过可用屏幕空间,内容将自动变为可滚动。
AloeStackView
提供了一套全面的方法来管理行,包括在开头和结尾插入行、在其他行的上方或下方插入行、隐藏和显示行、移除行以及检索行。
您可以使用 rowInset
属性以及 setInset(forRow:)
和 setInset(forRows:)
方法自定义行周围的间距。
AloeStackView.swift 中的类文档提供了所有可用 API 的完整详细信息。
AloeStackView
提供对处理行上的点击手势的支持
stackView.setTapHandler(
forRow: label,
handler: { [weak self] label in
self?.showAlert(title: "Row Tapped", message: "Tapped on: \(label.text ?? "")")
})
label.isUserInteractionEnabled = true
仅当行的 isUserInteractionEnabled
为 true
时,才会触发点击处理程序。
处理点击手势的另一种方法是遵循 Tappable
协议
public class ToggleLabel: UILabel, Tappable {
public func didTapView() {
textColor = textColor == .red ? .black : .red
}
}
for i in 1...3 {
let label = ToggleLabel()
label.text = "Label \(i)"
label.isUserInteractionEnabled = true
stackView.addRow(label)
}
遵循 Tappable
允许将常见的点击手势处理行为封装在视图内部。这样,您可以在 AloeStackView
中多次重用视图,而无需每次都编写相同的点击手势处理代码。
使用 AloeStackView
的优势之一是,即使在将视图添加到 AloeStackView
之后,您也可以保持对该视图的强引用。
如果您更改视图的某个属性,该属性会影响整体 UI 的布局,则 AloeStackView
将自动重新布局其所有行
stackView.setTapHandler(forRow: label, handler: { label in
label.text = (label.text ?? "") + "\n\nSome more text!"
})
如您所见,无需在更改视图之前或之后通知 AloeStackView
。Auto Layout 将确保 UI 保持最新状态。
默认情况下,AloeStackView
在行之间添加分隔符
您可以轻松隐藏添加到 AloeStackView
的任何行的分隔符
stackView.hidesSeparatorsByDefault = true
hidesSeparatorsByDefault
属性仅适用于新添加的行。AloeStackView
中已有的行不会受到影响。
您可以使用 hideSeparator(forRow:)
、hideSeparators(forRows:)
、showSeparator(forRow:)
和 showSeparators(forRows:)
方法隐藏或显示现有行的分隔符。
AloeStackView
还提供了一个方便的属性来自动隐藏最后一个分隔符
stackView.automaticallyHidesLastSeparator = true
您可以更改分隔符左右两侧的间距
stackView.separatorInset = .zero
在垂直方向上,仅使用 separatorInset
的 left 和 right 属性。
在水平方向上,分隔符垂直显示在行之间。在这种情况下,仅使用 separatorInset
的 top 和 bottom 属性,它们控制分隔符顶部和底部的间距。
与 hidesSeparatorsByDefault
一样,separatorInset
属性仅适用于新添加的行。AloeStackView
中已有的行不会受到影响。
您可以使用 setSeparatorInset(forRow:)
和 setSeparatorInset(forRows:)
方法更改现有行的分隔符插图。
AloeStackView
还提供了用于自定义分隔符颜色和宽度(或粗细)的属性
stackView.separatorColor = .blue
stackView.separatorWidth = 2
这些属性会影响 AloeStackView
中的所有分隔符。
AloeStackView
是一个开放类,因此很容易对其进行子类化,以添加自定义功能,而无需更改原始源代码。此外,AloeStackView
提供了两种方法,可用于进一步扩展其功能。
AloeStackView
中的每一行都包装在一个名为 StackViewCell
的 UIView
子类中。此视图用于逐行簿记,并管理诸如分隔符和插图之类的 UI。
每当向 AloeStackView
添加或插入一行时,都会调用 configureCell(_:)
方法。此方法将新创建的 StackViewCell
传递给该行。
您可以覆盖此方法以根据需要执行单元格的任何自定义,例如,支持您添加到 AloeStackView
的自定义功能或控制屏幕上行的外观。
此方法始终在单元格的任何默认值设置后调用,因此您在此方法中所做的任何更改都不会被系统覆盖。
每当将行插入到 AloeStackView
中时,都会调用 cellForRow(_:)
方法以获取该行的新单元格。默认情况下,cellForRow(_:)
仅返回一个新的 StackViewCell
,其中包含传入的行。
但是,StackViewCell
是一个开放类,可以对其进行子类化,以根据需要添加自定义行为和功能。要让 AloeStackView
使用您的自定义单元格,请覆盖 cellForRow(_:)
并返回自定义子类的实例。
提供自定义的 StackViewCell
子类可以更精细地控制行的显示方式。它还允许自定义数据与每行一起存储,这对于支持您添加到 AloeStackView
的任何功能非常有用。
要记住的一件事是,AloeStackView
会在从 cellForRow(_:)
返回单元格后将默认值应用于该单元格。因此,如果您需要对单元格应用任何进一步的自定义,则应考虑在 configureCell(_:)
中执行此操作。
这些方法共同为扩展 AloeStackView
以添加自定义行为和功能提供了相当大的灵活性。
例如,您可以向 AloeStackView
添加新方法来控制行的管理方式,或支持新型用户交互。您可以自定义 StackViewCell
上的属性来控制每行的外观。您可以对 StackViewCell
进行子类化,以将新数据和属性与每行一起存储,以便支持您添加的自定义功能。对 StackViewCell
进行子类化还可以更精细地控制行的显示方式。
但是,这种灵活性不可避免地会以复杂性和维护为代价进行权衡。AloeStackView
具有全面的 API,可以开箱即用地支持各种用例。因此,在诉诸扩展类以添加新功能之前,通常最好先查看所需行为是否可以通过现有 API 获得。这通常可以节省时间和精力,无论是开发自定义功能的成本还是持续维护。
AloeStackView
最适合用于内容少于一两个屏幕的较短屏幕。它特别适合用于接受用户输入、实现表单或由一组异构视图组成的屏幕。
但是,深入了解 AloeStackView
的技术细节也很有帮助,因为这可以帮助更好地理解适当的用例。
AloeStackView
是工具箱中非常有用的工具。其简单、灵活的 API 使您可以快速轻松地构建 UI。
与 UITableView
和 UICollectionView
不同,您可以在 AloeStackView
中保持对视图的强引用,并在任何时候对其进行更改。借助 Auto Layout,这将自动更新整个 UI - 无需将更改通知 AloeStackView
。
这使得 AloeStackView
非常适合表单和接受用户输入的屏幕等用例。在这些情况下,保持对用户正在编辑的字段的强引用,并使用验证反馈直接更新 UI 通常很方便。
AloeStackView
没有 reloadData
方法,也没有任何方法可以将其更改通知您的视图。这使其比 UITableView
之类的类更不容易出错且更易于调试。例如,如果未将对其管理的视图的底层数据的更改通知 AloeStackView
,则它不会崩溃。
由于 AloeStackView
在底层使用 UIStackView
,因此它不会在您滚动时回收视图。这消除了由于未正确回收视图而引起的常见错误。您也不需要独立维护用户与视图交互时的视图状态,这使得实现某些类型的 UI 更简单。
但是,AloeStackView
并非在所有情况下都适用。当屏幕加载时,AloeStackView
会在一次遍历中布局整个 UI。因此,较长的屏幕会在首次显示 UI 之前开始出现明显的延迟。这对用户来说不是很好的体验,并且会使应用感觉对导航操作无响应。因此,在实现内容超过一两个屏幕的 UI 时,不应使用 AloeStackView
。
放弃视图回收也是一种权衡:虽然 AloeStackView
可以更快地编写 UI 并且不易出错,但对于较长的屏幕,它的性能会更差,并且比 UITableView
之类的类使用更多的内存。因此,AloeStackView
通常不适用于包含许多相同类型视图(所有视图都显示相似数据)的屏幕。在这些情况下,UITableView
或 UICollectionView
之类的类通常表现更好。
可以使用 Carthage 安装 AloeStackView
。只需将 github "marlimox/AloeStackView"
添加到您的 Cartfile。
可以使用 CocoaPods 安装 AloeStackView
。只需将 pod 'AloeStackView'
添加到您的 Podfile。
对于最初旨在解决的用例,AloeStackView
的功能已经完备。但是,iOS 上的 UI 开发永远不是一个已解决的问题,我们预计会出现新的用例并发现旧的错误。
因此,我们完全欢迎贡献,包括新功能、功能请求、错误报告和修复。如果您想贡献,只需推送一个包含更改描述的 PR。您还可以为任何错误报告或功能请求提交 GitHub Issue。
如果您想联系,请随时发送电子邮件给项目维护者。如果您或您的公司发现此库有用,我们很乐意收到您的来信!
AloeStackView
由以下人员开发和维护:
Marli Oshlack (marli@oshlack.com)
AloeStackView
受益于许多其他工程师的贡献:
Daniel Crampton、Francisco Diaz、David He、Jeff Hodnett、Eric Horacek、Garrett Larson、Jasmine Lee、Isaac Lim、Jacky Lu、Noah Martin、Phil Nachum、Gonzalo Nuñez、Laura Skelton、Cal Stephens 和 Ortal Yahdav
此外,如果没有 Jordan Harband、Tyler Hedrick、Michael Bachand、Laura Skelton、Dan Federman 和 John Pottebaum 的帮助和支持,开源这个项目是不可能的。
AloeStackView
在 Apache License 2.0 下发布。有关详细信息,请参阅 LICENSE。
我们喜欢多肉植物,觉得这个名字很舒缓 😉