TextureGroup / Texture

Smooth asynchronous user interfaces for iOS apps.
https://texturegroup.org/
Other
8.02k stars 1.29k forks source link

ASDisplayNode in ASCornerLayoutSpec in ASCellNode: preferredSize's width not working #2073

Open Pranoy1c opened 1 year ago

Pranoy1c commented 1 year ago

I am very new to Texture/AsyncDisplayKit. I am able to reproduce the issue with this simple code.

I basically want to show a 10x10 square at the bottom right of the ASCellNode. I am doing this via a ASDisplayNode which is being set as the corner of a ASCornerLayoutSpec. I have set the style.preferredSize of the ASDisplayNode to CGSize(width: 10, height: 10).

For some reason, the width is not working and showing up as 50% of the screen width:

enter image description here

Code:

import UIKit
import AsyncDisplayKit

class ViewController: ASDKViewController<ASDisplayNode>, ASTableDataSource {

    var tableNode = ASTableNode()

    override init() {
        super.init(node: tableNode)

        node.automaticallyRelayoutOnSafeAreaChanges = true
        node.automaticallyManagesSubnodes = true
        tableNode.dataSource = self
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

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

    func tableNode(_ tableNode: ASTableNode, nodeBlockForRowAt indexPath: IndexPath) -> ASCellNodeBlock {
        let cellNodeBlock = { () -> ASCellNode in
            let cellNode = CellNode()
            return cellNode
        }

        return cellNodeBlock
    }

}

class CellNode: ASCellNode {
    fileprivate let titleNode = ASTextNode()
    fileprivate let savedIconNode = ASDisplayNode()

    override init() {
        super.init()
        self.automaticallyManagesSubnodes = true
        titleNode.attributedText = NSAttributedString(string: "This is my title!", attributes: [.font : UIFont.systemFont(ofSize: 20),.foregroundColor:UIColor.white])

        savedIconNode.isLayerBacked = true
        savedIconNode.backgroundColor = .green
        savedIconNode.style.preferredSize = CGSize(width: 10, height: 10)
    }

    override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
        let paddingToUse = 15.0;
        let contentView = ASInsetLayoutSpec(insets: UIEdgeInsets(top: paddingToUse, left: paddingToUse, bottom: paddingToUse, right: paddingToUse), child: ASStackLayoutSpec(direction: .horizontal, spacing: 5, justifyContent: .spaceBetween, alignItems: .notSet, children: [titleNode]))

        let contentViewAndSaveTriangle = ASCornerLayoutSpec(child: contentView, corner: savedIconNode, location: .bottomRight)

        return contentViewAndSaveTriangle
    }
}

Any idea what am I doing wrong?

VAndrJ commented 1 year ago

ASCornerLayoutSpec is not the best solution for the cell, as part of the node will be cut off even with clipsToBounds = false:

Issue example

As an option, a combination of ASOverlayLayoutSpec and ASRelativeLayoutSpec may be suitable:

override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec {
    let paddingToUse = 15.0;
    let contentView = ASInsetLayoutSpec(insets: UIEdgeInsets(top: paddingToUse, left: paddingToUse, bottom: paddingToUse, right: paddingToUse), child: ASStackLayoutSpec(direction: .horizontal, spacing: 5, justifyContent: .spaceBetween, alignItems: .notSet, children: [titleNode]))

    return ASOverlayLayoutSpec(
        child: contentView,
        overlay: ASRelativeLayoutSpec(
            horizontalPosition: .end,
            verticalPosition: .end,
            sizingOption: .minimumSize,
            child: savedIconNode
        )
    )
}

Result:

Result example