swiftasyncdisplaykit

How to set the ratio of a child ASNetworkImageNode


I have a ASViewControllerthat renders an ASTableNode.

I'd like to use an ASNetworkImageNode in each row to render an image.

I know the width / height so am able to set the ratio correctly. As such I am using ASRatioLayoutSpec on the image.

The issue I am having is, I will be including the ASNetworkImageNode and other child nodes in my row.

How can I set the ratio correctly in my layoutSpecThatFits method?

If I change it as follows:

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

    let ratio: CGFloat = props.size.height / props.size.width
    let imageRatioSpec = ASRatioLayoutSpec(ratio: ratio, child: self.imageNode)
    return imageRatioSpec

}

It works perfect, however I can't return any other child nodes this way.

I was expecting something like:

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

    let ratio: CGFloat = props.size.height / props.size.width
    let imageRatioSpec = ASRatioLayoutSpec(ratio: ratio, child: self.imageNode)


    return ASStackLayoutSpec(
        direction: .horizontal,
        spacing: 16,
        justifyContent: .start,
        alignItems: .center,
        children: [imageRatioSpec, textNode] // returns image and text
    )
}

But doesn't show the image, or at the very least does not set a ratio so the image is not visible.

import AsyncDisplayKit

class FeedNodeController: ASViewController<ASTableNode> {
        var data = [
        FeedItem(url: "https://pbs.twimg.com/media/EAtM2HyXUAEXJkA.jpg", size: .init(width: 1200, height: 800)),
        FeedItem(url: "https://pbs.twimg.com/media/EAtBZzOXUAEqeNJ.jpg", size: .init(width: 680, height: 510)),
        FeedItem(url: "https://pbs.twimg.com/media/EAsxYhlXoAArJe7.jpg", size: .init(width: 680, height: 453)),
        FeedItem(url: "https://pbs.twimg.com/media/EAss0ACXoAAUtlc.jpg", size: .init(width: 1115, height: 1200))
    ]

    init() {
        super.init(node: FeedTableNode())
    }

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

    override func viewDidLoad() {
        super.viewDidLoad()

        node.dataSource = self
        node.delegate = self
        node.view.tableFooterView = UIView()
    }
}

extension FeedNodeController:  ASTableDataSource, ASTableDelegate {
    func numberOfSections(in tableNode: ASTableNode) -> Int {
        return 1
    }

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

    func tableNode(_ tableNode: ASTableNode, nodeBlockForRowAt indexPath: IndexPath) -> ASCellNodeBlock {
        let props = data[indexPath.row]

        let nodeBlock: ASCellNodeBlock = { () -> ASCellNode in
            return FeedCellNode(props)
        }
        return nodeBlock
    }
}

class FeedTableNode: ASTableNode { }

class FeedCellNode: ASCellNode {

    private var props: FeedItem

    private lazy var imageNode: ASNetworkImageNode = {
        let node = ASNetworkImageNode()
        return node
    }()

    init(_ props: FeedItem) {
        self.props = props
        super.init()

        automaticallyManagesSubnodes = true
        imageNode.url = props.url
        addSubnode(imageNode)
    }

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

        let ratio: CGFloat = props.size.height / props.size.width
        let imageRatioSpec = ASRatioLayoutSpec(ratio: ratio, child: self.imageNode)

        return ASStackLayoutSpec(
            direction: .horizontal,
            spacing: 16,
            justifyContent: .start,
            alignItems: .center,
            children: [imageRatioSpec]
        )
    }
}



struct FeedItem {
    var url: URL
    var size: CGSize

    init(url: String, size: CGSize) {
        self.url = URL(string: url)!
        self.size = size
    }
}

Solution

  • You need to change your ASStackLayoutSpec to be a vertical stack.

       return ASStackLayoutSpec(
                direction: .vertical,
                spacing: 16,
                justifyContent: .start,
                alignItems: .center,
                children: [imageRatioSpec, textNode]
            )