我向各个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;
}
然后我调用[self positionImage: layer:]
将CALayer
拉伸到它的最大边界(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:
被调用太多次,这意味着我必须进行不必要的冗余计算,而且我不能使用viewWillStartLiveResize:
,因为我需要不断地将图像保持在正确的位置。我在俯瞰什么?
答案 0 :(得分:3)
setNeedsDisplayInRect:
。我首先确保我在我的应用程序中使用了自动布局,然后实现了以下内容:
subLayer.layoutManager = [CAConstraintLayoutManager layoutManager];
subLayer.autoresizingMask = kCALayerHeightSizable | kCALayerWidthSizable;
subLayer.contentsGravity = kCAGravityResizeAspect;
基本上,我将子图层autoResizingMask
设置为水平和垂直拉伸,然后设置contentsGravity
以保留纵横比。
我偶然发现的最后一个变量,但值得注意的是,您可以only use a few contentsGravity
constants if,就像我的情况一样,您将NSImage
设置为图层&#39 ; s contents
:
该方法创建的图像适合用作图层的内容,并支持所有图层的重力模式。相比之下,NSImage类仅支持kCAGravityResize,kCAGravityResizeAspect和kCAGravityResizeAspectFill模式。
当复杂的解决方案可以简化为3行代码时,总是很有趣。