我正在尝试实现一个动画,该动画以水平排列显示/隐藏视图。我希望这种情况可以在幻灯片上发生,并且不更改透明度。我到处都在使用自动布局。
至关重要的是,包含视图的总宽度随窗口而变化。因此,基于常量的动画是不可能的(或者,我相信,但很高兴被证明是错误的)。
|- viewA -|- viewB -|
我的第一个尝试是使用NSStackView
并为安排的子视图的isHidden
属性设置动画。尽管看似可以解决问题,但我仍无法完成任何接近我追求的事情。
我的第二个尝试是应用两个约束,一个约束将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()
}
}
还有一些潜在的相关问题,但到目前为止却无济于事:
Animating Auto Layout changes concurrently with NSPopover contentSize change