Objective c OSX上的CATiledLayers

Objective c OSX上的CATiledLayers,objective-c,macos,calayer,nsscrollview,Objective C,Macos,Calayer,Nsscrollview,这让我抓狂。。我有一个大的图像,需要一个既可缩放又可滚动的视图(理想情况下,它也应该可以旋转,但我已经放弃了这一部分)。由于图像非常大,我计划使用CATiledLayer,但我就是无法让它工作。 我的要求是: 我需要能够缩放(鼠标中心)和平移 图像不应更改其宽高比(不应调整大小,仅应缩放) 这应该运行在Mac OS 10.9(而不是iOS!) 内存使用量不应该太大(尽管高达100MB也可以) 我有必要的图像都在一个文件中完成,也分为许多(甚至有它为不同的缩放级别)。我更喜欢使用磁贴,因为这在

这让我抓狂。。我有一个大的图像,需要一个既可缩放又可滚动的视图(理想情况下,它也应该可以旋转,但我已经放弃了这一部分)。由于图像非常大,我计划使用CATiledLayer,但我就是无法让它工作。 我的要求是:

  • 我需要能够缩放(鼠标中心)和平移

  • 图像不应更改其宽高比(不应调整大小,仅应缩放)

  • 这应该运行在Mac OS 10.9(而不是iOS!)

  • 内存使用量不应该太大(尽管高达100MB也可以)

我有必要的图像都在一个文件中完成,也分为许多(甚至有它为不同的缩放级别)。我更喜欢使用磁贴,因为这在内存上应该更容易,但这两个选项都可用

大多数在线示例都涉及iOS,因此使用UIScrollView进行缩放/平移,但我无法复制NSScrollView的这种行为。我找到的Mac OS X的唯一例子是,但他的缩放总是在左下角,而不是中间,当我调整代码以使用png文件而不是pdf文件时,内存使用量大约为400 MB

这是我迄今为止最好的尝试:

@implementation MyView{
    CATiledLayer *tiledLayer;
}
-(void)awakeFromNib{
    NSLog(@"Es geht los");
    tiledLayer = [CATiledLayer layer];

    // set up this view & its layer
    self.wantsLayer = YES;
    self.layer = [CALayer layer];
    self.layer.masksToBounds = YES;
    self.layer.backgroundColor = CGColorGetConstantColor(kCGColorWhite);

    // set up the tiled layer
    tiledLayer.delegate = self;
    tiledLayer.levelsOfDetail = 4;
    tiledLayer.levelsOfDetailBias = 5;
    tiledLayer.anchorPoint = CGPointZero;
    tiledLayer.bounds = CGRectMake(0.0f, 0.0f, 41*256, 22*256);
    tiledLayer.autoresizingMask = kCALayerNotSizable;
    tiledLayer.tileSize = CGSizeMake(256, 256);
    self.frame = CGRectMake(0.0f, 0.0f, 41*256, 22*256);
    self.layer = tiledLayer;
    //[self.layer addSublayer:tiledLayer];
    [tiledLayer setNeedsDisplay];

}

-(void)drawRect:(NSRect)dirtyRect{
    CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];


    CGFloat scale = CGContextGetCTM(context).a;

    CGSize tileSize = tiledLayer.tileSize;


    tileSize.width /= scale;
    tileSize.height /= scale;

    // calculate the rows and columns of tiles that intersect the rect we have been asked to draw
    int firstCol = floorf(CGRectGetMinX(dirtyRect) / tileSize.width);
    int lastCol = floorf((CGRectGetMaxX(dirtyRect)-1) / tileSize.width);
    int firstRow = floorf(CGRectGetMinY(dirtyRect) / tileSize.height);
    int lastRow = floorf((CGRectGetMaxY(dirtyRect)-1) / tileSize.height);

    for (int row = firstRow; row <= lastRow; row++) {
        for (int col = firstCol; col <= lastCol; col++) {
            NSImage *tile = [self tileForScale:scale row:row col:col];
            CGRect tileRect = CGRectMake(tileSize.width * col, tileSize.height * row,
                                         tileSize.width, tileSize.height);

            // if the tile would stick outside of our bounds, we need to truncate it so as
            // to avoid stretching out the partial tiles at the right and bottom edges
            tileRect = CGRectIntersection(self.bounds, tileRect);

            [tile drawInRect:tileRect];
        }
    }
}

-(BOOL)isFlipped{
    return YES;
}
@实现MyView{
CATiledLayer*平铺层;
}
-(无效)从NIB中唤醒{
NSLog(@“Es geht los”);
平铺层=[CATiledLayer层];
//设置此视图及其图层
self.wantsLayer=是;
self.layer=[CALayer layer];
self.layer.masksToBounds=是;
self.layer.backgroundColor=CGColorGetConstantColor(kCGColorWhite);
//设置平铺层
tiledLayer.delegate=self;
tiledLayer.levelsOfDetail=4;
tiledLayer.levelsOfDetailBias=5;
tiledLayer.anchorPoint=CGPointZero;
tiledLayer.bounds=CGRectMake(0.0f,0.0f,41*256,22*256);
tiledLayer.autoresizingMask=kCalayerNotSize;
tiledLayer.tileSize=CGSizeMake(256,256);
self.frame=CGRectMake(0.0f,0.0f,41*256,22*256);
self.layer=平铺层;
//[self.layer addSublayer:tiledLayer];
[平铺层设置需要显示];
}
-(void)drawRect:(NSRect)dirtyRect{
CGContextRef上下文=[[NSGraphicsContext currentContext]GraphicsSport];
CGFloat scale=CGContextGetCTM(上下文).a;
CGSize tileSize=tiledLayer.tileSize;
tileSize.width/=比例;
tileSize.height/=刻度;
//计算与要求我们绘制的矩形相交的平铺行和列
int firstCol=floorf(CGRectGetMinX(dirtyRect)/tileSize.width);
int lastCol=floorf((CGRectGetMaxX(dirtyRect)-1)/tileSize.width);
int firstRow=地板(CGRectGetMinY(dirtyRect)/tileSize.height);
int lastRow=地板((CGRectGetMaxY(dirtyRect)-1)/tileSize.height);

对于(int row=firstRow;row经过大量的研究和尝试,我最终通过示例实现了这一点。我决定将其发布以供将来参考。打开ZIP>CoreAnimationLayers>TiledLayers,这里有一个很好的示例。这就是CATiledLayer如何与OS X一起工作的,因为那里的示例无法很好地处理缩放,所以我离开这里我的缩放代码

-(void)magnifyWithEvent:(NSEvent *)event{
    [super magnifyWithEvent:event];

    if (!isZooming) {
        isZooming = YES;

        BOOL zoomOut = (event.magnification > 0) ? NO : YES;

        if (zoomOut) {
            [self zoomOutFromPoint:event.locationInWindow];

        } else {
            [self zoomInFromPoint:event.locationInWindow];;
        }

    }

}

-(void)zoomInFromPoint:(CGPoint)mouseLocationInWindow{
    if(zoomLevel < pow(2, tiledLayer.levelsOfDetailBias)) {
        zoomLevel *= 2.0f;

        tiledLayer.transform = CATransform3DMakeScale(zoomLevel, zoomLevel, 1.0f);
        tiledLayer.position = CGPointMake((tiledLayer.position.x*2) - mouseLocationInWindow.x, (tiledLayer.position.y*2) - mouseLocationInWindow.y);

    }

}

-(void)zoomOutFromPoint:(CGPoint)mouseLocationInWindow{
    NSInteger power = tiledLayer.levelsOfDetail - tiledLayer.levelsOfDetailBias;
    if(zoomLevel > pow(2, -power)) {
        zoomLevel *= 0.5f;

        tiledLayer.transform = CATransform3DMakeScale(zoomLevel, zoomLevel, 1.0f);
        tiledLayer.position = CGPointMake((tiledLayer.position.x + mouseLocationInWindow.x)/2, (tiledLayer.position.y + mouseLocationInWindow.y)/2);

    }
}
-(无效)放大WithEvent:(NSEvent*)事件{
[超大型WithEvent:event];
如果(!正在缩放){
isZooming=是;
BOOL zoomOut=(event.放大率>0)?否:是;
如果(zoomOut){
[self zoomOutFromPoint:event.locationInWindow];
}否则{
[self zoomInFromPoint:event.locationInWindow];;
}
}
}
-(void)zoomInFromPoint:(CGPoint)鼠标定位InWindow{
if(zoomLevelpow(2,-功率)){
zoomLevel*=0.5f;
tiledLayer.transform=CATTransferorm3dMakeScale(zoomLevel,zoomLevel,1.0f);
tiledLayer.position=CGPointMake((tiledLayer.position.x+mouseLocationInWindow.x)/2,(tiledLayer.position.y+mouseLocationInWindow.y)/2);
}
}