1

I have an NSScrollView, whose documentView is a huge NSView, made of many many sub-NSImageViews, who act as tiles in a map. (The entire map is the NSView, and since it is way bigger than the screen size, its embedded in a scrollview).

I'm able to display the map with correct tile positions, and scroll around with the bars/gestures. However.. when I enable magnification to be able to zoom, the following happens: enter image description here Somehow I'm assuming auto-layout adds the tile borders below, and I don't know how to disable them. These are surely borders, since I have checked thousands of times that my tiles and subviews are the same size.. so where does this come from? I have quite some experience with iOS development, but am completely lost with NSScrollView (Where are my delegate methods?). How do I disable this behavior of the scroll view?

Here's my subview code:

- (void)setupSubViews
{
  NSLog(@"--------Creating subviews!-------");
    //first we create the subviews..
    //This is the key part, we traverse from top Left, and since OS X coordinates start at bottom left, we need to invert the rows!
    for (int i=0; i< NUMBER_OF_COLUMNS; i++) {
        for (int j=NUMBER_OF_ROWS-1; j>=0; j--) {
            CGRect frame = CGRectMake(i*256, j*256, 256, 256);
            NSImageView *newView = [[NSImageView alloc] initWithFrame:frame];
            newView.focusRingType = NSFocusRingTypeNone; //I gave this focusRing a try, it didn't work :(

            [self addSubview:newView];
        }
    }

}

And this is where I connect the subviews to the actual images..

-(void)updateMap:(id)tilesPassed{

    if (downloadFinished) {
        NSLog(@"--------DRAW RECT-------------");
        NSImageView *subView;
        NSInteger idx = 0;

        for (int i =0; i<[self.subviews count]; i++) {
            subView = [self.subviews objectAtIndex:i];
            [subView setAllowsCutCopyPaste:NO];
            [subView setImageFrameStyle:NSImageFrameNone]; //This doesnt work either :(

            MapTile *tile = [tilesArray objectAtIndex:idx];
            subView.image = tile.image;

            idx++;
        }
    }
}
Johannes Fahrenkrug
  • 42,912
  • 19
  • 126
  • 165
Cutetare
  • 913
  • 8
  • 24
  • That really looks like a drawing artifact as opposed to a "border" being intentionally drawn. Depending on your zoom level, you may need to make a slightly larger image to make sure that pixel rounding isn't causing you to be asked to draw slightly smaller images than necessary to draw the right area. – gaige Dec 24 '13 at 14:53
  • My problem is: This whole thing needs to be zoomable (working). If I only use zoom level 1, and turn Magnification off, I see no lines. They only appear once I zoom.. – Cutetare Dec 25 '13 at 01:27

2 Answers2

6

You probably don't want to use subviews for this. There is a CALayer subclass for exactly this purpose: CATiledLayer: https://developer.apple.com/library/mac/documentation/GraphicsImaging/Reference/CATiledLayer_class/Introduction/Introduction.html

With it you can even load different image tiles based on how far you are zoomed in, just like Google Maps. It will render without borders and the performance will be WAY better than using lots of subviews. Subviews are expensive, layers are (generally) cheap.

Update: This example will get you up and running: http://bill.dudney.net/roller/objc/entry/catiledlayer_example

Johannes Fahrenkrug
  • 42,912
  • 19
  • 126
  • 165
  • I have come to the conclusion that CATiledLayer probably is a good approach to my problem, but I simply can't get it to work (mostly because of the zoom), and didn't really find good sample code either..The only example provided by Apple is for UIScrollView (PhotoScroller), and I need it for Mac OSX... Could you maybe help me convert that project? – Cutetare Jan 02 '14 at 02:03
  • @Cutetare This blog post should get you up and running, complete with a sample project: http://bill.dudney.net/roller/objc/entry/catiledlayer_example – Johannes Fahrenkrug Jan 02 '14 at 13:55
  • Zoom doesn't work in that example (believe me, I've found/played with it already :P) – Cutetare Jan 02 '14 at 14:31
  • @Cutetare For me it zooms when I click on it. You might have to change the code to support pinch and zoom gestures. – Johannes Fahrenkrug Jan 02 '14 at 15:08
  • But it zooms to the lower left corner always, not to the mouse click. ANd I can't get the anchor point to change to each mouse click – Cutetare Jan 03 '14 at 02:02
  • I have accepted the answer because the bounty will expire, and I do believe that CATiledLayer is the best approach (after having researched many), but if you could help me with that implementation, it would be awesome :) – Cutetare Jan 03 '14 at 02:02
0

As a quick work around without using CATiledLayer you can stitch all images as one image and add it to main view

Below is the sample code to stitch 2 images:

UIImage *bottomImage = [UIImage imageNamed:@"bottom.png"]; //first image
UIImage *image       = [UIImage imageNamed:@"top.png"]; //foreground image

CGSize newSize = CGSizeMake(209, 260); //size of image view
UIGraphicsBeginImageContext( newSize );

// drawing 1st image
[bottomImage drawInRect:CGRectMake(0,0,newSize.width/2,newSize.height/2)];

// drawing the 2nd image after the 1st
[image drawInRect:CGRectMake(0,newSize.height/2,newSize.width/2,newSize.height/2)] ;

UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

and directly add this newImage formed by stitching all your tiled images to the main view.

venkat530
  • 43
  • 2
  • 10
  • This question is for Mac OS X AppKit. No UIImage ;) – Cutetare Jan 02 '14 at 03:50
  • you may try this link http://stackoverflow.com/questions/6541764/using-nsimageview-to-display-multiple-images-in-quick-sucession – venkat530 Jan 02 '14 at 04:10
  • Would this approach of yours support zoom?? How would I implement the zoom for that? – Cutetare Jan 02 '14 at 04:25
  • instead of NSImageView you can use the [IKImageView](https://developer.apple.com/library/mac/documentation/graphicsimaging/Reference/IKImageView/IKImageView_Reference.html) as your main image view. After the entire image stitched and embedded into the IKImageView you can do image editing operations such as rotating, zooming, and cropping. – venkat530 Jan 02 '14 at 04:49