Last active
December 26, 2019 05:02
-
-
Save GeekTree0101/5503552a4242450ea4efda2e3b473ef5 to your computer and use it in GitHub Desktop.
LayoutSpecBuildable.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() }) | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Layout spec function builder convention
https://github.com/muukii/TextureSwiftSupport/blob/master/TextureSwiftSupport/SpecBuilder.swift