TextureGroup / Texture

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

safeAreaInset not correctly pass to child node #2025

Open jeffersonsetiawan opened 3 years ago

jeffersonsetiawan commented 3 years ago

What

The SafeAreaInset of children node is not same as parent when add/change the node. as you can see in the video, once we change the rootNode to NodeB, the safeAreaInset for node B is 0 (reflected by button position is different)

Video

https://user-images.githubusercontent.com/14871122/133426120-010a119d-8d30-49fb-a573-576e68028145.mov

Code

class ChangeNodeVC: ASDKViewController<ASDisplayNode> {
    private var rootNode: ASDisplayNode = NodeA()
    override init() {
        super.init(node: ASDisplayNode())
        node.automaticallyManagesSubnodes = true
        node.automaticallyRelayoutOnSafeAreaChanges = true
        node.layoutSpecBlock = { [weak self] _, _ in
            guard let self = self else { return ASLayoutSpec() }
            return ASWrapperLayoutSpec(layoutElement: self.rootNode)
        }
    }

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

    override func viewDidLoad() {
        super.viewDidLoad()
       // simulate change the node after 2 seconds
        DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
            self.rootNode = NodeB()
            self.node.setNeedsLayout()
        }
    }
}
// Node
class NodeA: ASDisplayNode {
    private let button = ASButtonNode()

    override init() {
        super.init()
        automaticallyManagesSubnodes = true
        automaticallyRelayoutOnSafeAreaChanges = true
        button.setAttributedTitle(NSAttributedString(string: "HELLO WORLD FROM NODE A!"), for: .normal)
        button.backgroundColor = .blue
        backgroundColor = .red
    }

    override func layoutSpecThatFits(_: ASSizeRange) -> ASLayoutSpec {
        let relative = ASRelativeLayoutSpec(horizontalPosition: .center, verticalPosition: .end, sizingOption: .minimumSize, child: button)
        return ASInsetLayoutSpec(insets: .init(top: 0, left: 0, bottom: safeAreaInsets.bottom, right: 0), child: relative)
    }
}

class NodeB: ASDisplayNode {
    private let button = ASButtonNode()

    override init() {
        super.init()
        automaticallyManagesSubnodes = true
        automaticallyRelayoutOnSafeAreaChanges = true
        button.setAttributedTitle(NSAttributedString(string: "HELLO WORLD FROM NODE B!"), for: .normal)
        button.backgroundColor = .blue
        backgroundColor = .green
    }

    override func layoutSpecThatFits(_: ASSizeRange) -> ASLayoutSpec {
        print("<<< NodeB safeAreaInsets: ", safeAreaInsets.bottom)
        let relative = ASRelativeLayoutSpec(horizontalPosition: .center, verticalPosition: .end, sizingOption: .minimumSize, child: button)
        return ASInsetLayoutSpec(insets: .init(top: 0, left: 0, bottom: safeAreaInsets.bottom, right: 0), child: relative)
    }
}

Using Texture 3 Xcode 12.4/12.5, iOS 14.4+

Pranoy1c commented 6 months ago

Did you find a solution?

jeffersonsetiawan commented 6 months ago

Did you find a solution?

I fix it by getting the safeAreaInset from the top viewcontroller, not from self