objective-c - 在窗口调整大小时调整 CALayer 框架大小的方法?

标签 objective-c cocoa core-animation

我将一系列图像绘制到各个 CALayer 子图层,然后将这些子图层添加到 superlayer:

- (void)renderImagesFromArray:(NSArray *)array {
    CALayer *superLayer = [CALayer layer];
    for (id object in array) {
        CALayer* subLayer = [CALayer layer];
        // Disregard...
        NSURL *path = [NSURL fileURLWithPathComponents:@[NSHomeDirectory(), @"Desktop", object]];
        NSImage *image = [[NSImage alloc] initWithContentsOfURL:path];
        [self positionImage:image layer:subLayer];
        subLayer.contents = image;
        subLayer.hidden = YES;
        [superLayer addSublayer:subLayer];
    }
    [self.view setLayer:superLayer];
    [self.view setWantsLayer:YES];
    // Show top layer
    CALayer *top = superLayer.sublayers[0];
    top.hidden = NO;
}

然后,我调用 [selfpositionImage:layer:]CALayer 拉伸(stretch)到其最大边界 ( essentially using the algorithm for the CSS cover property ),并将其放置在窗口的中心:

- (void)positionImage:(NSImage *)image layer:(CALayer *)layer{
    float imageWidth = image.size.width;
    float imageHeight = image.size.height;
    float frameWidth = self.view.frame.size.width;
    float frameHeight = self.view.frame.size.height;
    float aspectRatioFrame = frameWidth/frameHeight;
    float aspectRatioImage = imageWidth/imageHeight;
    float computedImageWidth;
    float computedImageHeight;
    float verticalSpace;
    float horizontalSpace;
    if (aspectRatioImage <= aspectRatioFrame){
        computedImageWidth = frameHeight * aspectRatioImage;
        computedImageHeight = frameHeight;
        verticalSpace = 0;
        horizontalSpace = (frameWidth - computedImageWidth)/2;
    } else {
        computedImageWidth = frameWidth;
        computedImageHeight = frameWidth / aspectRatioImage;
        horizontalSpace = 0;
        verticalSpace = (frameHeight - computedImageHeight)/2;
    }
    [CATransaction flush];
    [CATransaction begin];
    CATransaction.disableActions = YES;
    layer.frame = CGRectMake(horizontalSpace, verticalSpace, computedImageWidth, computedImageHeight);
    [CATransaction commit];
}

这一切都工作正常,除非窗口大小被调整。我通过子类化 NSView 解决了这个问题(以一种非常丑陋的方式),然后实现了窗口大小调整时实际调用的唯一方法,viewWillDraw::

- (void)viewWillDraw{
    [super viewWillDraw];
    [self redraw];
}

- (void)redraw{
    AppDelegate *appDelegate = (AppDelegate *)[[NSApplication sharedApplication] delegate];
    CALayer *superLayer = self.layer;
    NSArray *sublayers = superLayer.sublayers;
    NSImage *image;
    CALayer *current;
    for (CALayer *view in sublayers){
        if (!view.isHidden){
            current = view;
            image = view.contents;
        }
    }
    [appDelegate positionImage:image layer:current];
}

那么...正确的方法是什么? viewWillDraw: get 被调用了太多次,这意味着我必须进行不必要和多余的计算,并且我不能使用 viewWillStartLiveResize: 因为我需要不断地将图像保持在其状态正确的位置。我忽略了什么?

最佳答案

彼得·霍西是对的;我原来的方法很笨拙,我不应该覆盖 setNeedsDisplayInRect:。我首先确保我在应用程序中使用自动布局,然后实现以下内容:

subLayer.layoutManager  = [CAConstraintLayoutManager layoutManager];
subLayer.autoresizingMask = kCALayerHeightSizable | kCALayerWidthSizable;
subLayer.contentsGravity = kCAGravityResizeAspect;

基本上,我将子图层的 autoResizingMask 设置为水平和垂直拉伸(stretch),然后设置 contentsGravity 以保留宽高比。

最后一个变量是我偶然发现的,但值得注意的是,您可以 only use a few contentsGravity constants if ,就像在我的例子中一样,您将 NSImage 设置为图层的 contents:

That method creates an image that is suited for use as the contents of a layer and that is supports all of the layer’s gravity modes. By contrast, the NSImage class supports only the kCAGravityResize, kCAGravityResizeAspect, and kCAGravityResizeAspectFill modes.

当复杂的解决方案可以简化为 3 行代码时,总是很有趣。

关于objective-c - 在窗口调整大小时调整 CALayer 框架大小的方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24100389/

相关文章:

cocoa - 手动绘制NSView的 subview

ios - CATransform3D 让我的 UITextView 消失?

ios - 如何使 uiscrollview 仅适用于 ios 的垂直滚动?

cocoa - NSString 赋值和保留

objective-c - 自动调整标签大小

cocoa - 在其他 View 上拖动时未释放 MouseDragged

objective-c - 当一个 Action 已经在进行时,用一个按钮开始一个 Action

objective-c - 如何完美计算 UILabel 所需的高度,其中属性字符串包含 HTML 标记

ios - 在 Objective-C 中解析 HTML

ios - 如何在自定义的tableViewController中转换到另一个viewController?