3

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

首先,我的窗口有一个设置为 NSImageScaleProportionallyUpOrDown 的 3x3 NSImageViews 网格。将内容压缩设置为 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 以正确的宽度和高度在全视图之间正确设置动画。但是当回去的时候有一些非常奇怪的事情......还有另一个视图,从原点动画到同一个目的地。我不知道如何有另一个动画视图。我什至检查了 self.view 的子视图数量,它是 10,但我看到 11.... 9 个网格视图,soloview 和这个幽灵视图。是的,创建主视图时我有 self.view.wantsLayer = YES 。

我一定要疯了。两种代码都不起作用。我讨厌为这样一个简单的任务使用约束。我宁愿使用基于框架的代码……白天和黑夜都简单得多,但我不知道为什么会有另一个视图向后移动。

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

任何帮助将不胜感激。

4

0 回答 0