Skip to content

Instantly share code, notes, and snippets.

@GeekTree0101
Last active December 26, 2019 05:02
Show Gist options
  • Save GeekTree0101/5503552a4242450ea4efda2e3b473ef5 to your computer and use it in GitHub Desktop.
Save GeekTree0101/5503552a4242450ea4efda2e3b473ef5 to your computer and use it in GitHub Desktop.
LayoutSpecBuildable.swift
extension ASLayoutElementStyle {
@discardableResult
func shrink(value: CGFloat = 1.0) -> Self {
self.flexShrink = value
return self
}
@discardableResult
func grow(value: CGFloat = 1.0) -> Self {
self.flexGrow = value
return self
}
@discardableResult
func nonShrink() -> Self {
self.flexShrink = 0.0
return self
}
@discardableResult
func nonGrow() -> Self {
self.flexGrow = 0.0
return self
}
@discardableResult
func width(_ value: CGFloat, unit: ASDimensionUnit = .points) -> Self {
self.width = ASDimension.init(unit: unit, value: value)
return self
}
@discardableResult
func height(_ value: CGFloat, unit: ASDimensionUnit = .points) -> Self {
self.height = ASDimension.init(unit: unit, value: value)
return self
}
@discardableResult
func maxWidth(_ value: CGFloat, unit: ASDimensionUnit = .points) -> Self {
self.maxWidth = ASDimension.init(unit: unit, value: value)
return self
}
@discardableResult
func maxHeight(_ value: CGFloat, unit: ASDimensionUnit = .points) -> Self {
self.maxHeight = ASDimension.init(unit: unit, value: value)
return self
}
@discardableResult
func minWidth(_ value: CGFloat, unit: ASDimensionUnit = .points) -> Self {
self.minWidth = ASDimension.init(unit: unit, value: value)
return self
}
@discardableResult
func minHeight(_ value: CGFloat, unit: ASDimensionUnit = .points) -> Self {
self.minHeight = ASDimension.init(unit: unit, value: value)
return self
}
@discardableResult
func size(_ value: CGSize) -> Self {
self.preferredSize = value
return self
}
@discardableResult
func maxSize(_ value: CGSize) -> Self {
self.maxSize = value
return self
}
@discardableResult
func minSize(_ value: CGSize) -> Self {
self.minSize = value
return self
}
@discardableResult
func spacingAfter(_ value: CGFloat) -> Self {
self.spacingAfter = value
return self
}
@discardableResult
func spacingBefore(_ value: CGFloat) -> Self {
self.spacingBefore = value
return self
}
}
enum LayoutSpecBuildableOptions {
case safeArea
case layoutMargins
}
protocol LayoutSpecBuildable {
var layoutSpec: ASLayoutSpec { get }
}
private var layoutSpecBuildableConstrainedSizeKey: String = "LayoutSpecBuildable.constrainedSize"
extension LayoutSpecBuildable where Self: ASDisplayNode {
var constraintedSize: ASSizeRange {
get {
return (objc_getAssociatedObject(
self,
&layoutSpecBuildableConstrainedSizeKey
) as? ASSizeRange) ?? ASSizeRangeUnconstrained
}
set {
objc_setAssociatedObject(
self,
&layoutSpecBuildableConstrainedSizeKey,
newValue,
.OBJC_ASSOCIATION_RETAIN_NONATOMIC
)
}
}
func automaticallyManagesLayoutSpecBuilder(changeSet: LayoutSpecBuildableOptions...) {
self.automaticallyManagesSubnodes = true
self.automaticallyRelayoutOnSafeAreaChanges = changeSet.contains(.safeArea)
self.automaticallyRelayoutOnLayoutMarginsChanges = changeSet.contains(.layoutMargins)
self.layoutSpecBlock = { [weak self] (_, sizeRange) -> ASLayoutSpec in
self?.constraintedSize = sizeRange
return self?.layoutSpec ?? ASLayoutSpec()
}
}
}
import Foundation
import AsyncDisplayKit
import BonMot
final class TestNode: ASDisplayNode, LayoutSpecBuildable {
private enum Const {
static let titleStyle: StringStyle = .init(
.font(UIFont.boldSystemFont(ofSize: 30.0)),
.color(UIColor.darkGray),
.alignment(.center)
)
static let subTitleStyle: StringStyle = .init(
.font(UIFont.systemFont(ofSize: 18.0)),
.color(UIColor.gray),
.alignment(.center),
.lineSpacing(4.0)
)
static let buttonTitleStyle: StringStyle = .init(
.font(UIFont.boldSystemFont(ofSize: 16.0)),
.color(UIColor.white)
)
static func contentInsets(safeAreaInsets: UIEdgeInsets) -> UIEdgeInsets {
return .init(
top: safeAreaInsets.top + UIScreen.main.bounds.height * 0.2,
left: safeAreaInsets.left,
bottom: safeAreaInsets.bottom + 40.0,
right: safeAreaInsets.right
)
}
}
// MARK: - UI Components
private lazy var titleNode: ASTextNode2 = {
let node = ASTextNode2()
node.attributedText = "Title".styled(with: Const.titleStyle)
return node
}()
private lazy var subTitleNode: ASTextNode2 = {
let node = ASTextNode2()
node.attributedText = "Sub-Title".styled(with: Const.subTitleStyle)
return node
}()
private lazy var writeButtonNode: ASButtonNode = {
let node = ASButtonNode()
node.backgroundColor = .orange
node.contentEdgeInsets = .init(top: 16.0, left: 24.0, bottom: 16.0, right: 24.0)
node.setAttributedTitle(
"Button".styled(with: Const.buttonTitleStyle),
for: .normal
)
node.cornerRadius = 8.0
return node
}()
// MARK: - Props
public var isHiddenTitleAndSubTitle: Bool = false
override init() {
super.init()
self.backgroundColor = .white
self.automaticallyManagesLayoutSpecBuilder(changeSet: .safeArea)
}
// MARK: - LayoutSpec
var layoutSpec: ASLayoutSpec {
LayoutSpec {
InsetLayout(insets: Const.contentInsets(safeAreaInsets: safeAreaInsets)) {
VStackLayout(spacing: 0.0, justifyContent: .spaceBetween, alignItems: .center) {
contentLayoutSpec
writeButtonNode
}
}
}
}
private var contentLayoutSpec: ASLayoutSpec {
if self.isHiddenTitleAndSubTitle {
return LayoutSpec {
EmptyLayout()
}
} else {
return LayoutSpec {
VStackLayout(spacing: 8.0, justifyContent: .start, alignItems: .center) {
titleNode.styled({ $0.shrink() })
subTitleNode.styled({ $0.shrink() })
}
}
}
}
}
@GeekTree0101
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment