Swift Readjust / Resize layout (ASDisplayNode) on show hide of children node

Posted

技术标签:

【中文标题】Swift Readjust / Resize layout (ASDisplayNode) on show hide of children node【英文标题】:Swift Readjust / Resize layout (ASDisplayNode) on show hide of the children node 【发布时间】:2019-07-12 09:54:02 【问题描述】:

我是 AsyncDisplayKit 的新手。所以,我创建了一个新的应用程序来学习基于我真实项目代码的 AsyncDisplayKit animationTransition。 显示/隐藏动画效果完美,但我不知道为什么父节点(ASDisplayNode)在孩子隐藏时没有重新调整布局(对不起,如果我的英语不好)

我已经尝试将 setNeedsLayout() 放在 transitionLayout 测量完成上,但没有任何改变

import AsyncDisplayKit

class HomeView: ASDisplayNode 
    let topWrapperNode: TopWrapperNode
    let loginButtonNode: LoginButtonNode

    override required init() 
        self.topWrapperNode = TopWrapperNode()
        self.loginButtonNode = LoginButtonNode()

        super.init()

        self.automaticallyManagesSubnodes = true
        self.automaticallyRelayoutOnSafeAreaChanges = true
        self.insetsLayoutMarginsFromSafeArea = true
    

    override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec 
        let verticalStackSpec = ASStackLayoutSpec.vertical()

        verticalStackSpec.children = [
            self.topWrapperNode,
            self.loginButtonNode
        ]
        verticalStackSpec.alignItems = .stretch
        verticalStackSpec.justifyContent = .spaceBetween

        let displayInset = ASInsetLayoutSpec(
            insets: UIEdgeInsets(top: 0, left: 32, bottom: 16, right: 32),
            child: verticalStackSpec
        )

        return ASInsetLayoutSpec(insets: safeAreaInsets, child: displayInset)
    

    func keyboardShowUpdateLayout(keyboardHeight: CGFloat) 
//        self.topWrapperNode.hideWelcomeLabelNode()
    

    func keyboardHideUpdateLayout() 
//        self.topWrapperNode.showWelcomeLabelNode()
    


// MARK - TopWrapperNode
class TopWrapperNode: ASDisplayNode 
    let welcomeLabelNode: WelcomeLabelNode
//    let textFieldNode: TextFieldNode

    override required init() 
        welcomeLabelNode = WelcomeLabelNode()
//        textFieldNode = TextFieldNode()

        super.init()

        self.automaticallyManagesSubnodes = true
        self.autoresizesSubviews = true
    

    override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec 
        let verticalStackSpec = ASStackLayoutSpec.vertical()

        verticalStackSpec.children = [
            self.logoImage,
            self.welcomeLabelNode,
//            self.textFieldNode,
        ]
        verticalStackSpec.alignItems = .stretch
        verticalStackSpec.justifyContent = .spaceBetween

        self.backgroundColor = .yellow

        let displayInset = ASInsetLayoutSpec(
            insets: UIEdgeInsets(top: 24, left: 0, bottom: 0, right: 0),
            child: verticalStackSpec
        )

        return ASInsetLayoutSpec(insets: safeAreaInsets, child: displayInset)
    

    private let logoImage: ASImageNode = 
        let imageNode = ASImageNode()

        imageNode.image = UIImage(named: "logo")
        imageNode.frame.size = CGSize(
            width: CGFloat(SizeScaler().moderateScale(size: 98)),
            height: CGFloat(SizeScaler().moderateScale(size: 48))
        )
        imageNode.contentMode = .scaleAspectFill
        imageNode.style.alignSelf = .center

        return imageNode
    ()

    func hideWelcomeLabelNode() 
        self.welcomeLabelNode.setHide(visibility: true)
        self.welcomeLabelNode.transitionLayout(withAnimation: true, shouldMeasureAsync: false)
    

    func showWelcomeLabelNode() 
        self.welcomeLabelNode.setHide(visibility: false)
        self.welcomeLabelNode.transitionLayout(withAnimation: true, shouldMeasureAsync: false)
    


// MARK: - WelcomeLabel
class WelcomeLabelNode: ASDisplayNode 
    var isHide: Bool = false

    override required init() 
        super.init()

        self.automaticallyManagesSubnodes = true
        self.autoresizesSubviews = true
        self.shouldAnimateSizeChanges = true
    

    override func layoutSpecThatFits(_ constrainedSize: ASSizeRange) -> ASLayoutSpec 
        let verticalStackSpec = ASStackLayoutSpec.vertical()

        verticalStackSpec.children = [self.welcomeTitleLabel, self.welcomeDescLabel]
        verticalStackSpec.alignItems = .start

        self.backgroundColor = .green

        return ASInsetLayoutSpec(
            insets: UIEdgeInsets(top: 0, left: 0, bottom: 40, right: 0),
            child: verticalStackSpec
        )
    

    override func animateLayoutTransition(_ context: ASContextTransitioning) 
        if (self.isHide) 
            let initialTitle = context.initialFrame(for: self.welcomeTitleLabel)
            let initialDesc = context.initialFrame(for: self.welcomeDescLabel)

            self.welcomeTitleLabel.alpha = 1
            self.welcomeTitleLabel.frame = initialTitle
            self.welcomeDescLabel.alpha = 1
            self.welcomeDescLabel.frame = initialDesc

            var finalTitle = context.finalFrame(for: self.welcomeTitleLabel)
            finalTitle.origin.y -= 50
            var finalDesc = context.finalFrame(for: self.welcomeDescLabel)
            finalDesc.origin.y -= 50

            UIView.animate(withDuration: 0.4, animations: 
                self.welcomeTitleLabel.alpha = 0
                self.welcomeTitleLabel.frame = finalTitle
                self.welcomeDescLabel.alpha = 0
                self.welcomeDescLabel.frame = finalDesc
            , completion:  finished in
                context.completeTransition(finished)
            )
         else 
            var finalTitle = context.finalFrame(for: self.welcomeTitleLabel)
            finalTitle.origin.y -= 50
            var finalDesc = context.finalFrame(for: self.welcomeDescLabel)
            finalDesc.origin.y -= 50

            self.welcomeTitleLabel.alpha = 0
            self.welcomeTitleLabel.frame = finalTitle
            self.welcomeDescLabel.alpha = 0
            self.welcomeDescLabel.frame = finalDesc

            let initialTitle = context.initialFrame(for: self.welcomeTitleLabel)
            let initialDesc = context.initialFrame(for: self.welcomeDescLabel)

            UIView.animate(withDuration: 0.4, animations: 
                self.welcomeTitleLabel.alpha = 1
                self.welcomeTitleLabel.frame = initialTitle
                self.welcomeDescLabel.alpha = 1
                self.welcomeDescLabel.frame = initialDesc
            , completion:  finished in
                context.completeTransition(finished)
            )
        
    

    let welcomeTitleLabel: QlueWorkLabel = 
        let label = QlueWorkLabel()

        label.setFont34(text: "Selamat datang!", fontType: "medium")
        label.textContainerInset = UIEdgeInsets(top: 32, left: 0, bottom: 8, right: 0)
        label.style.flexGrow = 1
        label.style.flexShrink = 1
        label.backgroundColor = .cyan

        return label
    ()

    let welcomeDescLabel: QlueWorkLabel = 
        let label = QlueWorkLabel()

        label.setFont16or20(
            text: "Pantau pekerjaanmu lebih mudah dengan QlueWork",
            fontType: "regular"
        )
        label.style.flexGrow = 1
        label.style.flexShrink = 1
        label.backgroundColor = .blue

        return label
    ()

    func setHide(visibility: Bool) 
        self.isHide = visibility
    

我希望父节点在子节点像 flexBox 一样隐藏/显示时重新调整布局。 谁能帮助我或告诉我为什么我做错了?

【问题讨论】:

【参考方案1】:

渲染完成后,你不能指望parentNode 通过改变其子维度来调整自己

但您可以通过询问parentNode 重新渲染自身来完成工作 像这样

DispatchQueue.main.async
     parentNode.transitionLayout(withAnimation: false,
                            shouldMeasureAsync: true, 
                            measurementCompletion: nil)           


确保在 main thread 上运行 transitionLayout

快乐纹理

【讨论】:

以上是关于Swift Readjust / Resize layout (ASDisplayNode) on show hide of children node的主要内容,如果未能解决你的问题,请参考以下文章

Swift 5 MacOS Image Resize 内存问题

text ORCL - Voir l'espace que l'on peux gagner en faisant un resize de DBF(avec generation

std::vector中assign resize reserve的区别

.wrap()与resize函数一起使用时多次添加选择器

“L”的 Swift 数据类型代表啥?

JavaScript Iframe自动调整大小