我正在为我的一个应用程序创建一个自动布局友好的拆分视图类.它的各种功能之一是它可以折叠窗格,并且可以动画它们的崩溃,就像你可能已经看过NSSplitView那样.
由于我正在使用约束,我通过在窗格上放置一个必需的width =(当前宽度)约束,然后以动画方式将约束的常量设置为0来实现此目的:
- (NSLayoutConstraint*)newHiddenConstraintAnimated:(BOOL)animated {
    NSLayoutConstraint * constraint = [NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:NSWidth(self.view.frame)];
    constraint.priority = NSLayoutPriorityRequired;
    CABasicAnimation * anim = [CABasicAnimation animation];
    anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
    anim.duration = 0.2;
    constraint.animations = [NSDictionary dictionaryWithObject:anim forKey:@"constant"];
    [self.view addConstraint:constraint];
    [(animated ? constraint.animator : constraint) setConstant:0.0];
    return constraint;
}
这很好用.不幸的是,稍后扩展窗格并不是很好.
- (void)removeHiddenConstraintAnimated:(BOOL)animated {
    if(!animated) {
        [self.view removeConstraint:self.hiddenConstraint];
    }
    else {
        NSLayoutConstraint * constraint = self.hiddenConstraint;
        NSView * theView = self.view;
        [NSAnimationContext beginGrouping];
        [constraint.animator setConstant:self.width];
        [NSAnimationContext currentContext].completionHandler = ^{
            [theView …我正在制作一个视图(通过揭示它),之后我需要发布一个通知(一旦动画完成).然而,应用程序的设计方式,隐藏视图(通过动画)时会发出另一个通知.基本上我有一个'showView'和'hideView'方法.每个人都这样做:
    [NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
      [context setDuration: 0.25];
      [[myView animator] setAlphaValue: 0];
    } completionHandler:^{
       // post notification now
    }];
问题是在后台的另一个线程中,我有一个定期计时器,它执行"健全性检查"以查看是否需要隐藏视图(如果不需要).这是一种积极的方法,但必要的是应用程序的许多组件响应不同的事件和场景.由于这个原因,我有时会得到一个'竞争条件',用户点击了'showView',但同时我们的一个线程感觉应该立即隐藏视图.
当两者都在主线程上发布通知时,应用程序会在SpinLock中无限期挂起.如果我能够弄清楚上面的动画块是否被"取消"(即在同一视图上执行的另一个动画块),我可以完全避免这种情况.在这种情况下,我不会发布通知,这将不会强制检查.
长话短说:我需要能够检查动画成功结束后是否调用'completionHandler',或者是否取消了.我知道在iOS中这是可能的,但我在OS X中找不到任何方法.请帮忙.
理想情况下我需要类似的东西UIView.animateWithDuration,但我知道这不是macOS上可用的API.操作NSView的实际帧并为更改设置动画的最佳方法是什么?
我尝试过CABasicAnimation,但是这是在CALayer而不是视图本身上执行的.
我需要的是为实际的视图框架设置动画......(或者这可能是一种不好的做法,还有另一种选择吗?)
因此,经过一番挖掘,我发现了NSAnimationContext.然而,这似乎只是在两个状态之间插入/淡化,这不是我想要的感觉.
这是我的代码的一小部分示例:
override func mouseDown(with event: NSEvent) {
    let newSize = NSMakeRect(self.frame.origin.x,
                             self.frame.origin.y - 100,
                             self.frame.width, self.frame.height + 100)
    NSAnimationContext.runAnimationGroup({ (context) -> Void in
        context.duration = 0.5
        self.animator().frame = newSize
        }, completionHandler: {
            Swift.print("completed")
    })
}
我有一个简单的Swift macOS应用程序(使用Xcode 8.2.1),它包含一个NSButton.当我点击按钮时,我希望它在指定时间内淡出.我以为我可以使用,NSAnimationContext但无论我设置什么值context,按钮几乎立即淡出.这不是正确的方法吗?
class ViewController: NSViewController {
  @IBOutlet weak var basicButton: NSButton!
  override func viewDidLoad() {
    super.viewDidLoad()
  }
  @IBAction func basicButtonClicked(_ sender: NSButton) {
    NSAnimationContext.runAnimationGroup({ (context) in
      context.duration = 10.0
      self.basicButton.animator().alphaValue = 1
    }) { 
      self.basicButton.animator().alphaValue = 0
    }
  }
}
我有一个基本的Mac应用程序,该应用程序具有通过自动版式完成的视图动画:
?动画将使其看起来好像视图从右侧滑入。
动画自动版式更改的推荐方法是:
NSAnimationContext.runAnimationGroup()allowsImplicitAnimation为true动画块内view.layoutSubtreeIfNeeded()在动画块内调用我遵循了此建议,并且在macOS Sierra上一切正常,但是在macOS High Sierra上,动画不再发生。取而代之的是,视图在没有动画的情况下显示在其最终位置。
我找到了一种解决方法:我使用将动画安排在下一个运行循环周期中DispatchQueue.main.async。但是,这似乎是一种hack,我想知道这里是否还缺少其他东西。
这是我的实际代码:
private func appendSlideViewControllerAnimated(_ viewController:NSViewController, to viewToTheLeft:NSView)
{
    // Insert the new view on the very right, just outside the parent:
    viewController.view.frame = self.view.bounds
    viewController.view.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(viewController.view)
    viewController.view.topAnchor.constraint(     equalTo: view.topAnchor     ).isActive = true
    viewController.view.bottomAnchor.constraint(  equalTo: view.bottomAnchor  ).isActive = true
    viewController.view.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
    viewController.view.leadingAnchor.constraint(equalTo: viewToTheLeft.trailingAnchor).isActive = true
    // Update the layout after we just added the view …cocoa autolayout nsanimationcontext nsanimation macos-high-sierra
对于某些视图类型(包括)NSAnimationContext.runAnimationGroup(_:_:),按照NSAnimationContext文档中的演示使用动画框架原点和大小可以正常工作NSImageView。但是,NSButton除非我在动画后添加明确的帧大小更改,否则它不会按预期工作
动画帧大小 NSImageView
对于 NSImageView,以下内容按预期工作。它被移动到原点,并调整为 200x200:
NSAnimationContext.runAnimationGroup({(let context) -> Void in
    context.duration = 2.0
    // Get the animator for an NSImageView
    let a = self.theImage.animator()
    // Move and resize the NSImageView
    a.frame = NSRect(x: 0, y: 0, width: 200, height: 200)
}) {
    print("Animation done")
}
动画帧大小 NSButton
使用 NSButton 执行相同操作时,按钮将移动但不会调整大小:
NSAnimationContext.runAnimationGroup({(let context) -> Void in
    context.duration = 2.0
    // Get the …
    // wc here is an NSWindowController
    [NSAnimationContext beginGrouping];
    [[NSAnimationContext currentContext] setDuration:0.5f];
    if (duplication) {
        NSPoint origin = initialSize.origin;
        origin.y += initialSize.size.height;
        origin = [wc.window cascadeTopLeftFromPoint:origin];
        origin.y -= initialSize.size.height;
        //[[wc.window animator] setFrameOrigin:origin];   // Why setFrameOrigin and cascadeTopLeftFromPoint are not animated?
        initialSize.origin = origin;
        [[wc.window animator] setFrame:initialSize display:YES];
    }
    // This block should be invoked when all of the animations started above have completed or been cancelled.
    // For not to show the edit window till the duplication animation not finished
    [NSAnimationContext …cocoa ×5
swift ×3
animation ×2
autolayout ×2
macos ×2
objective-c ×2
caanimation ×1
nsanimation ×1
nsview ×1
swift3 ×1