0

I am learning AsyncDisplayKit/Texture. I am trying to create an ASTableNode with a custom cell.

I am struggling to understand how to properly set and anchor the nodes I create within my ExampleNode.

I have tried this

   override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {

        let stack = ASStackLayoutSpec.vertical()
        stack.children = textNode
        return stack
    }

But have an error

Cannot assign value of type 'ASTextNode' to type '[ASLayoutElement]?'

I then updated layoutSpecThatFits with

override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
  return ASStackLayoutSpec(
        direction: .horizontal,
        spacing: 16,
        justifyContent: .start,
        alignItems: .center,
        children: [textNode]
    )
}

But this has bumped the text right up against the left of the cell. No Spacing at all is applied.

enter image description here

I am struggling to find a decent guide on using this, so please forgive me if the answer is obvious.

What would be the correct way, using the below class, to add nodes to a cell?

import AsyncDisplayKit

final class FeedNodeController: ASViewController<ASDisplayNode> {

    var tableNode: ASTableNode {
        return node as! ASTableNode
    }

    private lazy var tableNodeProvider = FeedTableNodeProvider()

    init() {
        super.init(node: ASTableNode())
        tableNode.delegate = tableNodeProvider
        tableNode.dataSource = tableNodeProvider

        tableNode.view.tableFooterView = UIView()
    }

    required init?(coder aDecoder: NSCoder) {
        return nil
    }
}

class FeedTableNodeProvider: NSObject {
    private let feed = ["Foo", "Bar", "Boo", "Baz"]
}

extension FeedTableNodeProvider: ASTableDataSource, ASTableDelegate {

    func numberOfSections(in tableNode: ASTableNode) -> Int {
        return 1
    }
    func tableNode(_ tableNode: ASTableNode, nodeBlockForRowAt indexPath: IndexPath) -> ASCellNodeBlock {

        let node = { [unowned self] () -> ASCellNode in
            return ExampleNode(text: self.feed[indexPath.row])
        }

        return node
    }

    func tableNode(_ tableNode: ASTableNode, numberOfRowsInSection section: Int) -> Int {
        return feed.count
    }
}

class ExampleNode: ASCellNode {

    private lazy var textNode: ASTextNode = {
        let node = ASTextNode()
        node.backgroundColor = .blue
        return node
    }()

    init(text: String) {
        super.init()
        textNode.attributedText = NSAttributedString(string: text)
        backgroundColor = .purple
        addSubnode(textNode)
    }

    override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
        return ASStackLayoutSpec(
            direction: .horizontal,
            spacing: 16,
            justifyContent: .start,
            alignItems: .center,
            children: [textNode]
        )
    }
}
Tim J
  • 1,211
  • 1
  • 14
  • 31

2 Answers2

1

Take a look at the ASDKgram-Swift example in the texture repo, PhotoTableNodeCell.


import Foundation
import AsyncDisplayKit

class PhotoTableNodeCell: ASCellNode {

    // MARK: Properties

    let usernameLabel = ASTextNode()
    let timeIntervalLabel = ASTextNode()
    let photoLikesLabel = ASTextNode()
    let photoDescriptionLabel = ASTextNode()

    let avatarImageNode: ASNetworkImageNode = {
        let node = ASNetworkImageNode()
        node.contentMode = .scaleAspectFill
        // Set the imageModificationBlock for a rounded avatar
        node.imageModificationBlock = ASImageNodeRoundBorderModificationBlock(0, nil)
        return node
    }()

    let photoImageNode: ASNetworkImageNode = {
        let node = ASNetworkImageNode()
        node.contentMode = .scaleAspectFill
        return node
    }()

    // MARK: Lifecycle

    init(photoModel: PhotoModel) {
        super.init()

        automaticallyManagesSubnodes = true
        photoImageNode.url = URL(string: photoModel.url)
        avatarImageNode.url = URL(string: photoModel.user.profileImage)
        usernameLabel.attributedText = photoModel.attributedStringForUserName(withSize: Constants.CellLayout.FontSize)
        timeIntervalLabel.attributedText = photoModel.attributedStringForTimeSinceString(withSize: Constants.CellLayout.FontSize)
        photoLikesLabel.attributedText = photoModel.attributedStringLikes(withSize: Constants.CellLayout.FontSize)
        photoDescriptionLabel.attributedText = photoModel.attributedStringForDescription(withSize: Constants.CellLayout.FontSize)
    }

    // MARK: ASDisplayNode

    override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {

        // Header Stack

        var headerChildren: [ASLayoutElement] = []

        let headerStack = ASStackLayoutSpec.horizontal()
        headerStack.alignItems = .center
        avatarImageNode.style.preferredSize = CGSize(
            width: Constants.CellLayout.UserImageHeight,
            height: Constants.CellLayout.UserImageHeight
        )
        headerChildren.append(ASInsetLayoutSpec(insets: Constants.CellLayout.InsetForAvatar, child: avatarImageNode))

        usernameLabel.style.flexShrink = 1.0
        headerChildren.append(usernameLabel)

        let spacer = ASLayoutSpec()
        spacer.style.flexGrow = 1.0
        headerChildren.append(spacer)

        timeIntervalLabel.style.spacingBefore = Constants.CellLayout.HorizontalBuffer
        headerChildren.append(timeIntervalLabel)

        let footerStack = ASStackLayoutSpec.vertical()
        footerStack.spacing = Constants.CellLayout.VerticalBuffer
        footerStack.children = [photoLikesLabel, photoDescriptionLabel]
        headerStack.children = headerChildren

        let verticalStack = ASStackLayoutSpec.vertical()
        verticalStack.children = [
            ASInsetLayoutSpec(insets: Constants.CellLayout.InsetForHeader, child: headerStack),
            ASRatioLayoutSpec(ratio: 1.0, child: photoImageNode),
            ASInsetLayoutSpec(insets: Constants.CellLayout.InsetForFooter, child: footerStack)
        ]
        return verticalStack
    }
}
Mycroft Canner
  • 1,828
  • 1
  • 11
  • 24
0

ASTexNode will calculate its width just for how long the text is if you don't set any width for it

don't really understand what you ask

if you want to add a padding, you can wrap you current ASStackLayoutSpec with ASInsetLayoutSpec

...
let mainStack = ASStackLayoutSpec(
            direction: .horizontal,
            spacing: 16,
            justifyContent: .start,
            alignItems: .center,
            children: [textNode])

let paddedMainStack = ASInsetLayoutSpec(insets: UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16), child: mainStack)

return paddedMainStack
...

then you will have your padding

Happy Texturing

Wendy Liga
  • 634
  • 5
  • 12