VATextureKit
Texture 库的包装器,增加了一些特性。
安装
CocoaPods
将以下内容添加到您的 Podfile 中:
pod 'VATextureKit'
在终端中的项目目录下:
pod install
或者只是试试示例项目
pod try 'VATextureKit'
布局规范
以下 LayoutSpec
DSL 组件可用于组合简单或非常复杂的布局。
VATextureKit | Texture |
---|---|
列 | ASStackLayoutSpec(垂直) |
行 | ASStackLayoutSpec(水平) |
堆叠 | |
安全区域 | ASInsetLayoutSpec(与安全区域边缘) |
内边距 | ASInsetLayoutSpec |
.包裹 | ASWrapperLayoutSpec |
.角落 | ASCornetLayoutSpec |
.安全 | ASInsetLayoutSpec(与安全区域边缘) |
.居中 | ASCenterLayoutSpec |
.比例 | ASRatioLayoutSpec |
.叠加 | ASOverlayLayoutSpec |
.背景 | ASBackgroundLayoutSpec |
.相对 | ASRelativeLayoutSpec |
.绝对 | ASAbsoluteLayoutSpec |
列
与 ASStackLayoutSpec
一起使用
override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
ASStackLayoutSpec(
direction: .vertical,
spacing: 8,
justifyContent: .start,
alignItems: .start,
children: [
firstRectangleNode,
secondRectangleNode,
]
)
}
与 Column
一起使用
override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
Column(spacing: 8) {
firstRectangleNode
secondRectangleNode
}
}
示例
行
与 ASStackLayoutSpec
一起使用
override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
ASStackLayoutSpec(
direction: .horizontal,
spacing: 4,
justifyContent: .spaceBetween,
alignItems: .start,
children: [
firstRectangleNode,
secondRectangleNode,
]
)
}
与 Row
一起使用
override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
Row(spacing: 4, main: .spaceBetween) {
firstRectangleNode
secondRectangleNode
}
}
示例
堆叠
堆叠
:
override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
Stack {
firstRectangleNode
secondRectangleNode
}
}
示例
安全区域
在 ASDisplayNode
中,automaticallyRelayoutOnSafeAreaChanges = true
的情况下的 ASStackLayoutSpec
override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
ASInsetLayoutSpec(
insets: UIEdgeInsets(
top: safeAreaInsets.top,
left: safeAreaInsets.left,
bottom: safeAreaInsets.bottom,
right: safeAreaInsets.right
),
child: ...
)
}
与 SafeArea
一起使用
override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
SafeArea {
...
}
}
内边距
与 ASInsetLayoutSpec
一起使用
ASInsetLayoutSpec(
insets: UIEdgeInsets(
top: 8,
left: 8,
bottom: 8,
right: 8
),
child: titleTextNode
)
与 .padding
一起使用
titleTextNode
.padding(.all(8))
.包裹
与 ASWrapperLayoutSpec
一起使用
ASWrapperLayoutSpec(layoutElement: imageNode)
与 .wrapped
一起使用
imageNode.wrapped()
.角落
与 ASWrapperLayoutSpec
一起使用
override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
let spec = ASCornerLayoutSpec(
child: imageNode,
corner: badgeNode,
location: .topRight
)
spec.offset = CGPoint(x: 4, y: 2)
spec.wrapsCorner = false
return spec
}
与 .corner
一起使用
imageNode
.corner(badgeNode, offset: CGPoint(x: 4, y: 2))
.安全
在 ASDisplayNode
中,automaticallyRelayoutOnSafeAreaChanges = true
的情况下的 ASStackLayoutSpec
override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
ASInsetLayoutSpec(
insets: UIEdgeInsets(
top: safeAreaInsets.top,
left: safeAreaInsets.left,
bottom: safeAreaInsets.bottom,
right: safeAreaInsets.right
),
child: listNode
)
}
与 .safe
一起使用
override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
listNode
.safe(in: self)
}
.居中
与 ASCenterLayoutSpec
一起使用
ASCenterLayoutSpec(
centeringOptions: .XY,
sizingOptions: .minimumXY,
child: buttonNode
)
与 .centered
一起使用
buttonNode
.centered()
.比例
与 ASRatioLayoutSpec
一起使用
ASRatioLayoutSpec(
ratio: 2 / 3,
child: imageNode
)
与 .ratio
一起使用
imageNode
.ratio(2 / 3)
.叠加
与 ASOverlayLayoutSpec
一起使用
ASOverlayLayoutSpec(
child: imageNode,
overlay: gradientNode
)
与 .overlay
一起使用
imageNode
.overlay(gradientNode)
.背景
与 ASOverlayLayoutSpec
一起使用
ASBackgroundLayoutSpec(
child: gradientNode,
background: imageNode
)
与 .background
一起使用
imageNode
.background(gradientNode)
.相对
与 ASOverlayLayoutSpec
一起使用
ASRelativeLayoutSpec(
horizontalPosition: .start,
verticalPosition: .end,
sizingOption: .minimumSize,
child: buttonNode
)
与 .relatively
一起使用
buttonNode
.relatively(horizontal: .start, vertical: .end)
.绝对
与 ASAbsoluteLayoutSpec
一起使用
buttonNode.style.preferredSize = frame.size
buttonNode.style.layoutPosition = frame.origin
return ASAbsoluteLayoutSpec(
sizing: .sizeToFit,
children: [buttonNode]
)
与 .absolutely
一起使用
buttonNode
.absolutely(frame: .frame, sizing: .sizeToFit)
更复杂的布局示例
与 VATextureKit
一起使用
override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
Column(cross: .stretch) {
Row(main: .spaceBetween) {
Row(spacing: 8, cross: .center) {
testNameTextNode
testInfoButtonNode
}
testStatusTextNode
}
titleTextNode
.padding(.top(8))
resultTextNode
.padding(.top(32))
.centered(.X)
resultUnitsTextNode
.centered(.X)
referenceResultBarNode
.padding(.vertical(24))
Row(spacing: 16, cross: .center) {
Column(spacing: 8) {
Row(spacing: 8) {
resultBadgeImageNode
resultDescriptionTextNode
}
referenceValuesTextNode
}
accessoryImageNode
}
}
.padding(.all(16))
}
与原始的 Texture
一起使用
override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
ASInsetLayoutSpec(
insets: UIEdgeInsets(
top: 16,
left: 16,
bottom: 16,
right: 16
),
child: ASStackLayoutSpec(
direction: .vertical,
spacing: 0,
justifyContent: .start,
alignItems: .stretch,
children: [
ASStackLayoutSpec(
direction: .horizontal,
spacing: 0,
justifyContent: .spaceBetween,
alignItems: .start,
children: [
ASStackLayoutSpec(
direction: .horizontal,
spacing: 8,
justifyContent: .start,
alignItems: .center,
children: [
testNameTextNode,
testInfoButtonNode,
]
),
testStatusTextNode,
]
),
ASInsetLayoutSpec(
insets: UIEdgeInsets(
top: 8,
left: 0,
bottom: 0,
right: 0
),
child: titleTextNode
),
ASCenterLayoutSpec(
centeringOptions: .X,
sizingOptions: .minimumXY,
child: ASInsetLayoutSpec(
insets: UIEdgeInsets(
top: 32,
left: 0,
bottom: 0,
right: 0
),
child: resultTextNode
)
),
ASCenterLayoutSpec(
centeringOptions: .X,
sizingOptions: .minimumXY,
child: resultUnitsTextNode
),
ASInsetLayoutSpec(
insets: UIEdgeInsets(
top: 24,
left: 0,
bottom: 24,
right: 0
),
child: referenceResultBarNode
),
ASStackLayoutSpec(
direction: .horizontal,
spacing: 0,
justifyContent: .start,
alignItems: .center,
children: [
ASStackLayoutSpec(
direction: .vertical,
spacing: 8,
justifyContent: .start,
alignItems: .start,
children: [
ASStackLayoutSpec(
direction: .horizontal,
spacing: 8,
justifyContent: .start,
alignItems: .start,
children: [
resultBadgeImageNode,
resultDescriptionTextNode,
]
),
referenceValuesTextNode,
]
),
accessoryImageNode,
]
),
]
)
)
}
修饰器
.sized
设置 Node
的大小。
使用 style
imageNode.style.width = ASDimension(unit: .points, value: 320)
imageNode.style.height = ASDimension(unit: .points, value: 480)
使用 .sized
imageNode
.sized(width: 320, height: 480)
.flex
设置 Node
的flex。
使用 style
titleTextNode.style.flexShrink = 0.1
titleTextNode.style.flexGrow = 1
使用 .flex
titleTextNode
.flex(shrink: 0.1, grow: 1)
.maxConstrained
设置 Node
的最大可能大小。
使用 style
titleTextNode.style.maxWidth = ASDimension(unit: .points, value: 320)
titleTextNode.style.maxHeight = ASDimension(unit: .points, value: 100)
使用 .maxConstrained
titleTextNode
.maxConstrained(width: 320, height: 480)
.minConstrained
设置 Node
的最小可能大小。
使用 style
titleTextNode.style.minWidth = ASDimension(unit: .points, value: 100)
titleTextNode.style.minHeight = ASDimension(unit: .points, value: 50)
使用 .minConstrained
titleTextNode
.minConstrained(width: 100, height: 50)
节点
VADisplayNode
ASDisplayNode
的一个子类,自动管理子节点并处理主题更新。
VATextNode
ASTextNode
的一个子类,处理内容大小和主题更新。具有默认的文本样式。
VAButtonNode
带有 onTap
闭包的 ASButtonNode
的一个子类。
VACellNode
ASCellNode
的一个子类,自动管理子节点并处理主题更新。
VAImageNode
具有参数化初始化器的 ASImageNode
的一个子类。
VASpacerNode
一个 ASDisplayNode
的子类,用于填充 Row / Column
中的空间。
VASafeAreaDisplayNode
一个子类,在安全区域变化时自动重排布局。
VABaseGradientNode
具有 CAGradientLayer
根层的 ASDisplayNode
的一个子类。
VALinearGradientNode
具有参数化初始化器的 VABaseGradientNode
的一个子类,简化线性渐变创建。
VARadialGradientNode
具有参数化初始化器的 VABaseGradientNode
的一个子类,简化径向渐变创建。
VAReadMoreTextNode
使用简便方式实现“阅读更多”截断的 VATextNode
的一个子类。
代码
lazy var readMoreTextNode = VAReadMoreTextNode(
text: .loremText,
maximumNumberOfLines: 2,
readMore: .init(
text: "Read more",
fontStyle: .headline,
colorGetter: { $0.systemBlue }
)
)
示例
容器
VATableListNode
一个用于声明式的 ASTableNode
的子类。
VAViewController
一个处理主题更新的 ASDKViewController
的子类。
VANavigationController
一个处理主题更新和内容大小变化的 ASDKNavigationController
的子类。
VATabBarController
一个处理主题更新的 ASTabBarController
的子类。
VAWindow
一个处理主题更新和内容大小变化的 VAWindow
的子类。提供应用上下文。
VAContainerCellNode
用于包装任何节点与 Cell 节点。
包装器
VAViewWrapperNode
用于使用节点包装 UIView
的容器。
VANodeWrapperView
用于使用视图包装节点的容器。
VASizedViewWrapperNode
用于使用节点和继承其大小的 UIView
的容器。
动画
布局过渡动画
以简单的方式实现布局过渡动画。只需编写
override func animateLayoutTransition(_ context: ASContextTransitioning) {
animateLayoutTransition(context: context)
}
示例
节点动画
以简单的方式实现节点动画。
示例
pulseNode.animate(.scale(values: [1, 1.1, 0.9, 1.2, 0.8, 1.1, 0.9, 1]), duration: 1)
结果
更多示例
主题
以简单的方式支持主题。默认支持浅色/深色或自定义初始化。
属性包装器
- Obs
- Relay(value:)(行为Relay)
- Relay()(发布Relay)
使用这些包装器,代码变得更简洁。
行为Relay
var someObs: Observable<String> { someRelay.asObservable() }
private let someRelay = BehaviorRelay<String>(value: "value")
...
someRelay.accept("value1")
变为
@Obs.Relay(value: "value")
var someObs: Observable<String>
...
_someObs.rx.accept("value1")
发布Relay
var someObs: Observable<String> { someRelay.asObservable() }
private let someRelay = PublishRelay<String>()
变为
@Obs.Relay()
var someObs: Observable<String>
扩展
ASDimension
支持初始化。
与原始的 Texture
一起使用
style.height = ASDimension(unit: .auto, value: 0)
style.height = ASDimension(unit: .points, value: height)
style.height = ASDimension(unit: .fraction, value: 0.3)
与 VATextureKit
一起使用
style.height = .auto
style.height = .points(height)
style.height = .fraction(0.3)
style.height = .fraction(percent: 30)
CGSize
数学
CGSize(width: 2, height: 2) * 2 = CGSize(width: 4, height: 4)
CGSize(width: 2, height: 2) + 1 = CGSize(width: 3, height: 3)
初始化器
CGSize(same: 16) == CGSize(width: 16, height: 16)
UIEdgeInsets
变量
/// (top, left)
origin: CGPoint
/// top + bottom
vertical: CGFloat
/// left + right
horizontal: CGFloat
初始化器
UIEdgeInsets(all: 16) == UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
UIEdgeInsets(vertical: 16) == UIEdgeInsets(top: 16, left: 0, bottom: 16, right: 0)
UIEdgeInsets(horizontal: 16) == UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16)
UIEdgeInsets(vertical: 4, horizontal: 8) == UIEdgeInsets(top: 4, left: 8, bottom: 4, right: 8)
预览
使用支持功能以简便方式预览节点
sRepresentation(layout:)