Animation 使用层视图设置约束动画

Animation 使用层视图设置约束动画,animation,autolayout,core-animation,appkit,Animation,Autolayout,Core Animation,Appkit,我正在尝试实现一个动画,以水平排列方式显示/隐藏视图。我希望这种情况发生在幻灯片上,并且不改变不透明度。我到处都在使用自动布局 关键的是,包含视图的总宽度随窗口的变化而变化。所以,持续的动画是不可能的(或者我相信是这样,但很高兴被证明是错误的) 我的第一次尝试是使用NSStackView,并设置排列子视图的ishiden属性的动画。尽管看起来它可能会起到作用,但我还是无法从我所追求的东西中得到任何东西 我的第二次尝试是应用两个约束,一个是强制viewB为零宽度,另一个是确保宽度相等。在动画中,我

我正在尝试实现一个动画,以水平排列方式显示/隐藏视图。我希望这种情况发生在幻灯片上,并且不改变不透明度。我到处都在使用自动布局

关键的是,包含视图的总宽度随窗口的变化而变化。所以,持续的动画是不可能的(或者我相信是这样,但很高兴被证明是错误的)

我的第一次尝试是使用
NSStackView
,并设置排列子视图的
ishiden
属性的动画。尽管看起来它可能会起到作用,但我还是无法从我所追求的东西中得到任何东西

我的第二次尝试是应用两个约束,一个是强制viewB为零宽度,另一个是确保宽度相等。在动画中,我将这些约束的优先级从defaultHigh更改为defaultLow

这会在两种情况下产生正确的布局,但动画不起作用

在包含视图上使用
wantsLayer=true
时,不会发生任何动画。视图只是跳转到它们的最终状态。如果没有
wantsLayer
,视图会产生动画。但是,当折叠时,viewA会进行一次很好的滑动,但viewB会立即消失。作为一个实验,我将零宽度更改为固定的
10.0
,这样,动画可以在两个方向上正常工作。但是,我希望视图完全隐藏

因此,有几个问题:

是否可以使用层背景视图设置这样的布局动画

有没有其他技术可以达到同样的效果

关于如何使用NSStackView很好地实现这些目标,有什么想法吗

class LayoutAnimationViewController: NSViewController {
    let containerView: NSView
    let view1: ColorView
    let view2: ColorView
    let widthEqualContraint: NSLayoutConstraint
    let widthZeroConstraint: NSLayoutConstraint

    init() {
        self.containerView = NSView()
        self.view1 = ColorView(color: NSColor.red)
        self.view2 = ColorView(color: NSColor.blue)

        self.widthEqualContraint = view2.widthAnchor.constraint(equalTo: view1.widthAnchor)
        widthEqualContraint.priority = .defaultLow

        self.widthZeroConstraint = view2.widthAnchor.constraint(equalToConstant: 0.0)
        widthZeroConstraint.priority = .defaultHigh

        super.init(nibName: nil, bundle: nil)
    }

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

    override func loadView() {
        self.view = containerView
//        view.wantsLayer = true

        view.addSubview(view1)
        view.addSubview(view2)
        view.subviewsUseAutoLayout = true

        NSLayoutConstraint.activate([
            view1.topAnchor.constraint(equalTo: view.topAnchor),
            view1.bottomAnchor.constraint(equalTo: view.bottomAnchor),
            view1.leadingAnchor.constraint(equalTo: view.leadingAnchor),
//            view1.trailingAnchor.constraint(equalTo: view2.leadingAnchor),

            view2.topAnchor.constraint(equalTo: view.topAnchor),
            view2.bottomAnchor.constraint(equalTo: view.bottomAnchor),
            view2.leadingAnchor.constraint(equalTo: view1.trailingAnchor),
            view2.trailingAnchor.constraint(equalTo: view.trailingAnchor),

            widthEqualContraint,
            widthZeroConstraint,
        ])
    }

    func runAnimation() {
        view.layoutSubtreeIfNeeded()

        self.widthEqualContraint.toggleDefaultPriority()
        self.widthZeroConstraint.toggleDefaultPriority()
//        self.leadingConstraint.toggleDefaultPriority()

        NSAnimationContext.runAnimationGroup({ (context) in
            context.allowsImplicitAnimation = true
            context.duration = 3.0

            self.view.layoutSubtreeIfNeeded()
        }) {
            Swift.print("animation complete")
        }
    }
}

extension LayoutAnimationViewController {
    @IBAction func runTest1(_ sender: Any?) {
        self.runAnimation()
    }
}
此外,还有一些可能相关但迄今没有帮助的相关问题:

class LayoutAnimationViewController: NSViewController {
    let containerView: NSView
    let view1: ColorView
    let view2: ColorView
    let widthEqualContraint: NSLayoutConstraint
    let widthZeroConstraint: NSLayoutConstraint

    init() {
        self.containerView = NSView()
        self.view1 = ColorView(color: NSColor.red)
        self.view2 = ColorView(color: NSColor.blue)

        self.widthEqualContraint = view2.widthAnchor.constraint(equalTo: view1.widthAnchor)
        widthEqualContraint.priority = .defaultLow

        self.widthZeroConstraint = view2.widthAnchor.constraint(equalToConstant: 0.0)
        widthZeroConstraint.priority = .defaultHigh

        super.init(nibName: nil, bundle: nil)
    }

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

    override func loadView() {
        self.view = containerView
//        view.wantsLayer = true

        view.addSubview(view1)
        view.addSubview(view2)
        view.subviewsUseAutoLayout = true

        NSLayoutConstraint.activate([
            view1.topAnchor.constraint(equalTo: view.topAnchor),
            view1.bottomAnchor.constraint(equalTo: view.bottomAnchor),
            view1.leadingAnchor.constraint(equalTo: view.leadingAnchor),
//            view1.trailingAnchor.constraint(equalTo: view2.leadingAnchor),

            view2.topAnchor.constraint(equalTo: view.topAnchor),
            view2.bottomAnchor.constraint(equalTo: view.bottomAnchor),
            view2.leadingAnchor.constraint(equalTo: view1.trailingAnchor),
            view2.trailingAnchor.constraint(equalTo: view.trailingAnchor),

            widthEqualContraint,
            widthZeroConstraint,
        ])
    }

    func runAnimation() {
        view.layoutSubtreeIfNeeded()

        self.widthEqualContraint.toggleDefaultPriority()
        self.widthZeroConstraint.toggleDefaultPriority()
//        self.leadingConstraint.toggleDefaultPriority()

        NSAnimationContext.runAnimationGroup({ (context) in
            context.allowsImplicitAnimation = true
            context.duration = 3.0

            self.view.layoutSubtreeIfNeeded()
        }) {
            Swift.print("animation complete")
        }
    }
}

extension LayoutAnimationViewController {
    @IBAction func runTest1(_ sender: Any?) {
        self.runAnimation()
    }
}