在有或没有约束的情况下使NSImageView / NSView动画化的问题

时间:2013-11-11 04:35:26

标签: cocoa animation constraints autolayout nsview

我正在尝试在使用AutoLayout的窗口(xib)中执行一些非常简单的视图动画,并且我得到了一些非常不可预测的结果。显然,自动布局引擎正在做一些事情,我不知道如何解决它。

首先,我的窗口有一个3x3 NSImageViews网格,设置为NSImageScaleProportionallyUpOrDown。将内容压缩设置为10后,在调整窗口大小时,视图会做正确的事情......所有内容都保持在正确的位置并且比例正确。一个漂亮的3x3网格图像。

当用户点击视图时,我希望视图接管整个窗口并淡出其他视图。然后,再次触摸时,将其设置回原始位置。

为了保持简单的约束,我决定将所有NSImageViews保留在原位并在触摸视图的顶部创建另一个并使用它来制作动画。这就是问题所在。

我尝试过两种方式为该视图设置动画:通过动画制作约束,并且不对该视图使用约束,只为其框架设置动画。无论哪种方式,我都会得到疯狂的结果。

以下是代码:

使用约束

- (void) moveToFullView:(NSInteger)which
{
self.soloIndex = which;
NSImageView *tmpView = self.imageviews[which];

// create a view directly on top of the touched view
self.soloView = [[NSImageView alloc] initWithFrame:tmpView.frame];
[self.soloView.translatesAutoresizingMaskIntoConstraints = NO;
self.soloView.image = tmpView.image;
self.soloView.imageScaling = NSImageScaleProportionallyUpOrDown;

// without this, the window changes size in moveBackFromFullView
[self.soloView setContentCompressionResistancePriority:10 forOrientation:NSLayoutConstraintOrientationHorizontal];
[self.soloView setContentCompressionResistancePriority:10 forOrientation:NSLayoutConstraintOrientationVertical];

[self.view addSubview:self.soloView];

// create constraints with animatable constants    
CGFloat leftSpace = tmpView.frame.origin.x;
CGFloat topSpace = tmpView.frame.origin.y;
CGFloat width =  tmpView.frame.size.width - self.view.bounds.size.width;
CGFloat height = tmpView.frame.size.height - self.view.bounds.size.height;

self.soloView.leftConstraint = [NSLayoutConstraint constraintWithItem:self.soloView
                                                              attribute:NSLayoutAttributeLeft
                                                              relatedBy:NSLayoutRelationEqual
                                                                 toItem:self.view
                                                              attribute:NSLayoutAttributeLeft
                                                             multiplier:1.0
                                                               constant:leftSpace];

self.soloView.topConstraint = [NSLayoutConstraint constraintWithItem:self.soloView
                                                             attribute:NSLayoutAttributeTop
                                                             relatedBy:NSLayoutRelationEqual
                                                                toItem:self.view
                                                             attribute:NSLayoutAttributeTop
                                                            multiplier:1.0
                                                              constant:topSpace];

self.soloView.widthConstraint = [NSLayoutConstraint constraintWithItem:self.soloView
                                                               attribute:NSLayoutAttributeWidth
                                                               relatedBy:NSLayoutRelationEqual
                                                                  toItem:self.view
                                                               attribute:NSLayoutAttributeWidth
                                                              multiplier:1.0
                                                                constant:width];

self.soloView.heightConstraint = [NSLayoutConstraint constraintWithItem:self.soloView
                                                                attribute:NSLayoutAttributeHeight
                                                                relatedBy:NSLayoutRelationEqual
                                                                   toItem:self.view
                                                                attribute:NSLayoutAttributeHeight
                                                               multiplier:1.0
                                                                 constant:height];

[self.view addConstraint:self.soloView.leftConstraint];
[self.view addConstraint:self.soloView.topConstraint];
[self.view addConstraint:self.soloView.widthConstraint];
[self.view addConstraint:self.soloView.heightConstraint];
[self.view layoutSubtreeIfNeeded];

// animate the view to occupy the entire self.view
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
    context.allowsImplicitAnimation = YES;
    context.duration = 0.75;

    // fade out the other views for now
    for(NSImageView *p in self.imageviews){
        p.alphaValue = 0;
    }

    // these values should make the soloView in the same place and size as the self.view
    self.soloView.leftConstraint.constant = 0;
    self.soloView.topConstraint.constant = 0;
    self.soloView.widthConstraint.constant = 0;
    self.soloView.heightConstraint.constant = 0;

    [self.view layoutSubtreeIfNeeded];
} completionHandler:nil];
}



- (void) moveBackFromFullView
{
// this is where the solo view should animate back to
NSRect destR = [self.imageviews[self.soloIndex] frame];


CGFloat leftSpace = destR.origin.x;
CGFloat topSpace = destR.origin.y;
CGFloat width =  destR.size.width - self.view.bounds.size.width;
CGFloat height = destR.size.height - self.view.bounds.size.height;

[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
    context.allowsImplicitAnimation = YES;
    context.duration = 0.75;

    for(NSImageView *p in self.imageviews){
        p.alphaValue = 1.00;
    }

    self.soloView.leftConstraint.constant = leftSpace;
    self.soloView.topConstraint.constant = topSpace;
    self.soloView.widthConstraint.constant = width;
    self.soloView.heightConstraint.constant = height;

    [self.view layoutSubtreeIfNeeded];
} completionHandler:^{
    [self.soloView removeFromSuperview];
    self.soloView = nil;
}];
}

使用上面基于约束的代码,soloView的左侧和顶部正确移动到完整视图并返回,但是当进入完整视图时,soloView的宽度和高度不会生成动画,并且似乎只保持目标大小。但是......它可以正确地返回......宽度和高度。

使用框架

- (void) moveToFullView:(NSInteger)which
{
self.soloIndex = which;
NSImageView *tmpView = self.imageviews[which];

self.soloView = [[NSImageView alloc] initWithFrame:tmpView.frame];
[self.soloView.translatesAutoresizingMaskIntoConstraints = NO;
self.soloView.imageScaling = NSImageScaleProportionallyUpOrDown;
self.soloView.image = tmpView.image;

self.soloView.autoresizingMask = NSViewHeightSizable | NSViewWidthSizable;

[self.view addSubview:self.soloView];

[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
    context.allowsImplicitAnimation = YES;
    context.duration = 0.75;

    for(NSImageView *p in self.imageviews){
        p.alphaValue = 0;
    }

    self.soloView.frame = NSMakeRect(0, 0, self.view.bounds.size.width, self.view.bounds.size.height);

} completionHandler:nil];
}



- (void) moveBackFromFullView
{
NSRect destR = [self.imageviews[self.soloIndex] frame];

[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
    context.allowsImplicitAnimation = YES;
    context.duration = 0.95;

    for(NSImageView *p in self.imageviews){
        p.alphaValue = 1.00;
    }

    self.soloView.frame = destR;

} completionHandler:^{
    [self.soloView removeFromSuperview];
    self.soloView = nil;
}];
}

使用上面基于帧的代码,soloView可以在全视图中正确地设置动画,并具有正确的宽度和高度。但回去时有一些非常奇怪的东西......还有另一个 ghost 视图,从原点到同一目的地的动画。我不知道如何有另一个动画视图。我甚至检查了self.view的子视图的数量,它是10,但我看到了11 .... 9个网格视图,独奏视图和这个鬼视图。是的,我在创建主视图时有self.view.wantsLayer = YES。

我一定是疯了。两个代码都不起作用。我讨厌使用约束来完成这么简单的任务。我宁愿使用基于帧的代码......日夜都要简单得多,但我不知道为什么会有另一种观点向后移动。

我对UIView动画有比NSView动画更多的经验,所以也许我缺少一些基本的东西。

非常感谢任何帮助。

0 个答案:

没有答案