【问题标题】:CATiledLayers on OS XOS X 上的 CATiledLayers
【发布时间】:2014-01-31 03:43:49
【问题描述】:

这让我发疯了。我有一个大图像,需要一个既可缩放又可滚动的视图(理想情况下它也应该能够旋转,但我已经放弃了这部分) .由于图像非常大,我打算使用 CATiledLayer,但我根本无法让它工作。 我的要求是:

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

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

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

  • 内存使用量不应该很大(尽管最多 100 MB 应该没问题)。

我在一个文件中完成了必要的图像,并且还平铺了许多(甚至具有不同的缩放级别)。我更喜欢使用磁贴,因为这应该更容易记忆,但两个选项都可用。

大多数在线示例都参考 iOS,因此使用 UIScrollView 进行缩放/平移,但我无法为 NSScrollView 复制该行为。找到的 Mac OS XI 的唯一示例是 this,但他的缩放总是转到左下角,而不是中间,当我调整代码以使用 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;
}

但这会使图像变形,并且不能正确缩放或平移(但至少平铺选择有效)......

我不敢相信这这么难,任何帮助将不胜感激。谢谢:)

【问题讨论】:

    标签: objective-c macos calayer nsscrollview


    【解决方案1】:

    经过大量研究和尝试,我终于设法使用this 示例使其工作。决定将其发布以供将来参考。打开 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);
    
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-03-03
      • 2010-11-27
      • 2010-10-03
      • 1970-01-01
      • 2015-12-24
      • 2011-08-24
      • 2012-08-09
      • 2014-04-09
      相关资源
      最近更新 更多