在 macOS objective-c 上为 NSView 约束(图层支持视图)设置动画

Animate NSView constraints (layer backed view) on macOS objective-c

我在 XCode 12,macOS,objective-c,而不是 iOS。

我有一个包含 3 个项目的菜单(水平堆栈视图):

蓝色下划线是通过编程方式创建的:

- (void)viewDidLoad {

    [super viewDidLoad];     
    [self createAnimatedLineAtButton:self.importButton];
}

// Create line
- (void)createAnimatedLineAtButton:(NSButton*)button {

    // This view is layer backed
    SHViewCustomBackground* underlineView = [[SHViewCustomBackground alloc] init];
    
    underlineView.backgroundColor = [NSColor colorNamed:@"color_spot"]; // blue color
    underlineView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:underlineView];
    self.underlineView = underlineView;    

    [self updateAnimatedLineUnderButton:self.importButton];
}

接下来的代码更新约束(最初调用上面的行创建),然后单击每个按钮。

- (void)updateAnimatedLineUnderButton:(NSButton *)button {
    
    // Constraints are stored here
    if (self.underlineConstraints) {
        [self.view removeConstraints:self.underlineConstraints];
    }

    [NSAnimationContext runAnimationGroup:^(NSAnimationContext *context){
        context.duration = 1;
        context.allowsImplicitAnimation = YES;
    
        NSView* underlineView = self.underlineView;
        NSDictionary *views = NSDictionaryOfVariableBindings(underlineView, button);
        self.underlineConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[button]-[underlineView(1)]" options:NSLayoutFormatAlignAllLeading | NSLayoutFormatAlignAllTrailing metrics:nil views:views];
        [self.view addConstraints:self.underlineConstraints];
    
        [self.view layoutSubtreeIfNeeded];
    } completionHandler:nil];    
}

这是按钮操作

- (IBAction)buttonClicked:(id)sender {
    
    [self updateAnimatedLineUnderButton:(NSButton*)sender];
}

现在我的问题是:当我按“导入”>“导出”>“导入”顺序单击按钮时,该行按预期从导入到导出并返回动画。每当我单击“占位符”(中间按钮)时,该行就会跳动并且不会设置动画。当我之后点击“导入”或“导出”时,它也会跳转。

我正在琢磨这里出了什么问题。所有按钮都正确连接,所有动作都正确触发。

编辑:比较所有按钮后,我发现导入和导出按钮(有效的地方)具有相同的宽度。

这是一个想法……行得通。最初我打算按照你的方式去做,但你可能不喜欢这样,最终动画化了两个约束。但效果很好。

这个想法与您的想法非常相似,但不同之处在于我创建了前导和尾随约束并为其设置了动画。

@implementation ViewController

- ( void ) viewDidLoad
{
    super.viewDidLoad;
    [self animateLine:self.longButton];
}

// Animate the line
- ( void ) animateLine:( NSButton * ) button
{
    [NSAnimationContext runAnimationGroup: ^ ( NSAnimationContext * context ) {

        context.duration = 1;
        context.allowsImplicitAnimation = YES;
        self.leadingConstraint.animator.constant = button.frame.origin.x;
        self.trailingConstraint.animator.constant = self.stackView.bounds.size.width - button.frame.origin.x - button.frame.size.width;
        NSLog ( @"Setting leading to %f trailing to %f", self.leadingConstraint.constant, self.trailingConstraint.constant );

        self.lineField.layoutSubtreeIfNeeded;

    }];
}

- ( IBAction ) buttonAction:( id ) sender
{
    [self animateLine:sender];
}

就是这样。其余的发生在情节提要中。我设置了约束,以便通过交换第一项和第二项的味道来使距离有意义。