ASDKFluentExtensions
ASDKFluentExtensions 是一组 Objective-C 分类,它为 Texture 提供了用于布局代码的流畅接口。这种流畅风格更直观,提高了可读性(更少需要查看视觉结构),并使布局更简洁且易于维护。它还允许布局规范和样式的 组合。
想象一下你想要叠加一张图像和渐变。然后将渐变叠加到标题上,该标题必须位于渐变的右下角,并且有一些内边距。最后,整个内容的宽高比应该是 1。使用 ASDKFluentExtensions,你可以编写如下布局代码
override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
return imageNode
.withOverlay(gradientNode
.withOverlay(titleNode
.withRelativePosition(horizontal: .end, vertical: .end)
.withInset(UIEdgeInsetsMake(.infinity, .infinity, 4, 4))))
.withRatio(1)
}
ASDisplayNode
和 ASLayoutSpec
子类都可以使用此流畅语法包裹在 ASLayoutSpec
中。只需开始键入 .with
并查找适当的补全
所有 ASDKFluentExtensions 方法都返回一个遵守 ASLayoutElement
协议的对象,因此流畅布局可以相互链接。此外,对 style
属性的修改也可以与布局定义组合起来。这样,信息以有意义的方式流动。以下是如何修改 flexGrow
和 alignSelf
的示例
func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
return ASStackLayoutSpec
.vertical()
.withSpacing(20)
.withJustifyContent(.center)
.withChildren([
topSeparator
.withFlexGrow(1.0),
textNode
.withAlignSelf(.center),
bottomSeparator
.withFlexGrow(1.0)
])
.withInset(UIEdgeInsets(top: 60, left: 0, bottom: 60, right: 0))
}
ASDKFluentExtensions 还提供了对 ASStackLayoutSpec
和 ASAbsoluteLayoutSpec
的分类,使其能够以非常可读的风格将规格内联到布局代码中
func fluentLayoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
return ASAbsoluteLayoutSpec()
.withSizing(.sizeToFit)
.withChildren([
photoNode
.withPreferredSize(CGSize(width: 150, height: 150))
.withLayoutPosition(CGPoint(x: 40 / 2.0, y: 40 / 2.0)),
iconNode
.withPreferredSize(CGSize(width: 40, height: 40))
.withLayoutPosition(CGPoint(x: 150, y: 0))])
}
甚至有一个方便创建间距的分类!
let header = ASStackLayoutSpec().withChildren([userName, ASLayoutSpec.spacer(), lastTimeOnline])
最后,这是一个更复杂的示例,将知名示例 ASDKgram-Swift 中的 PhotoTableNodeCell
的布局代码重新编写为使用流畅布局
func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
return ASStackLayoutSpec
.vertical()
.withChildren([
ASStackLayoutSpec()
.withAlignItems(.center)
.withChildren([
avatarImageNode
.withPreferredSize(CGSize(width: Constants.CellLayout.UserImageHeight, height: Constants.CellLayout.UserImageHeight))
.withInset(Constants.CellLayout.InsetForAvatar),
usernameLabel
.withFlexShrink(1),
ASLayoutSpec.spacer(),
timeIntervalLabel
.withSpacingBefore(Constants.CellLayout.HorizontalBuffer)
])
.withInset(Constants.CellLayout.InsetForHeader),
photoImageNode.withRatio(1),
ASStackLayoutSpec
.vertical()
.withSpacing(Constants.CellLayout.VerticalBuffer)
.withChildren([
photoLikesLabel,
photoDescriptionLabel])
.withInset(Constants.CellLayout.InsetForFooter)
])
}
此布局从上到下连续读取。最外层的代码定义了一般结构,内部部分定义了细节。信息以有意义的方式流动,因此需要更少的视觉扫描。此外,添加、删除和重新组织规范(例如在调试或原型设计期间)更快。最后,请注意如何将样式属性的修改与布局规范组合(请参阅与布局规范定义内联的 withPreferredSize
或 withFlexShrink
的用法)。这避免了如何使代码视觉上流畅的干扰。
关于流畅接口的更多信息
如果你想要了解更多关于流畅API的,请务必查看这篇论文,其中Martin Fowler和Eric Evans首次提出了这个术语。
文档
在这个Texture的分支中有关于如何使用ASDKFluentExtensions来编写流畅布局代码的几个示例。这些示例是主Texture仓库中现有示例的克隆,经过修改以展示ASDKFluentExtensions。目的是让人们想要接近这种流畅语法的可以有一系列熟悉的示例可供参考。
这是目前可用示例的列表
- ASDKgram-Swift
- LayoutSpecExamples-Swift
- LayoutSpecExamples
- ASViewController
- ASMapNode
- ASDKTube
- ASDKLayoutTransition
- ASCollectionView
- ASDKgram
安装
ASDKFluentExtensions目前支持Cocoapods和Carthage。
Cocoapods
你可以使用Cocoapods安装ASDKFluentExtensions。将以下pod添加到你的Podfile中
target 'MyApp' do
pod "ASDKFluentExtensions"
end
然后运行以下命令
$ pod install
务必导入头文件
#import <ASDKFluentExtensions/ASDKFluentExtensions.h>
Carthage
从版本0.6开始,你可以使用Carthage构建ASDKFluentExtensions。将以下行添加到你的Cartfile中
github "cesteban/ASDKFluentExtensions" >= 0.6
然后构建框架
carthage update
最后,按常规将生成的框架添加到你的项目中。
讨论
ASDKFluentExtensions 是对 ASDisplayNode
、ASLayoutSpec
、ASStackLayoutSpec
和 ASAbsoluteLayoutSpec
的一系列 Objective-C 分类,它创建并返回期望的布局规范,并将 self
作为子节点传递
- (ASOverlayLayoutSpec *)withOverlay:(id<ASLayoutElement>)overlay
{
return [ASOverlayLayoutSpec overlayLayoutSpecWithChild:self overlay:overlay];
}
ASDKFluentExtensions 还提供了一系列分类来修改 ASDisplayNode
或 ASLayoutSpec
的 style
属性,返回 self
- (instancetype)withPreferredSize:(CGSize)preferredSize
{
self.style.preferredSize = preferredSize;
return self;
}
这使得布局和样式变得 可组合,并使 API 非常易于阅读
代码重复和 Swift 协议扩展
为了为 ASDisplayNode
和 ASLayoutSpec
提供相同的功能,存在大量的代码重复。
这可以在 Swift 中通过在 ASLayoutElement
上使用协议扩展来避免,但这种情况下 API 将无法从 Objective-C 访问。另一方面,Texture
是一个纯 Objective-C 框架,因此使用 Swift 扩展它将引入限制。请查看这里 ASDKFluentExtensions 的原始 Swift 实现,非常早期就放弃了,转而使用当前的 Objective-C API。
贡献
发送您所有的反馈,并请贡献。对如何改进此组件的拉取请求和建议非常欢迎。