Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Well, Nicholas Riley's Solution is an ugly hack in that it addresses the wrong class; the issue isn't with <strong>NSClipView</strong> (which he subclassed, but which works just fine as is), but with <strong>IKImageView</strong>.</p> <p>The issue with <strong>IKImageView</strong> is actually quite simple (God knows why Apple hasn't fixed this in what? … 7 years ...): Its size does not adjust to the size of the image it displays. Now, when you embed an <strong>IKImageView</strong> in an <strong>NSScrollView</strong>, the scroll view obviously can only adjust its scroll bars relative to the size of the embedded <strong>IKImageView</strong>, not to the image it contains. And since the size of the <strong>IKImageView</strong> always stays the same, the scroll bars won't work as expected.</p> <p>The following code subclasses <strong>IKImageView</strong> and fixes this behavior. Alas, it won't fix the fact that <strong>IKImageView</strong> is crash-prone in Mountain Lion as soon as you zoom …</p> <pre><code>///////////////////// HEADER FILE - FixedIKImageView.h #import &lt;Quartz/Quartz.h&gt; @interface FixedIKImageView : IKImageView @end ///////////////////// IMPLEMENTATION FILE - FixedIKImageView.m #import "FixedIKImageView.h" @implementation FixedIKImageView - (void)awakeFromNib { [self setTranslatesAutoresizingMaskIntoConstraints:NO]; // compatibility with Auto Layout; without this, there could be Auto Layout error messages when we are resized (delete this line if your app does not use Auto Layout) } // FixedIKImageView must *only* be used embedded within an NSScrollView. This means that setFrame: should never be called explicitly from outside the scroll view. Instead, this method is overwritten here to provide the correct behavior within a scroll view. The new implementation ignores the frameRect parameter. - (void)setFrame:(NSRect)frameRect { NSSize imageSize = [self imageSize]; CGFloat zoomFactor = [self zoomFactor]; NSSize clipViewSize = [[self superview] frame].size; // The content of our scroll view (which is ourselves) should stay at least as large as the scroll clip view, so we make ourselves as large as the clip view in case our (zoomed) image is smaller. However, if our image is larger than the clip view, we make ourselves as large as the image, to make the scrollbars appear and scale appropriately. CGFloat newWidth = (imageSize.width * zoomFactor &lt; clipViewSize.width)? clipViewSize.width : imageSize.width * zoomFactor; CGFloat newHeight = (imageSize.height * zoomFactor &lt; clipViewSize.height)? clipViewSize.height : imageSize.height * zoomFactor; [super setFrame:NSMakeRect(0, 0, newWidth - 2, newHeight - 2)]; // actually, the clip view is 1 pixel larger than the content view on each side, so we must take that into account } //// We forward size affecting messages to our superclass, but add [self setFrame:NSZeroRect] to update the scroll bars. We also add [self setAutoresizes:NO]. Since IKImageView, instead of using [self setAutoresizes:NO], seems to set the autoresizes instance variable to NO directly, the scrollers would not be activated again without invoking [self setAutoresizes:NO] ourselves when these methods are invoked. - (void)setZoomFactor:(CGFloat)zoomFactor { [super setZoomFactor:zoomFactor]; [self setFrame:NSZeroRect]; [self setAutoresizes:NO]; } - (void)zoomImageToRect:(NSRect)rect { [super zoomImageToRect:rect]; [self setFrame:NSZeroRect]; [self setAutoresizes:NO]; } - (void)zoomIn:(id)sender { [super zoomIn:self]; [self setFrame:NSZeroRect]; [self setAutoresizes:NO]; } - (void)zoomOut:(id)sender { [super zoomOut:self]; [self setFrame:NSZeroRect]; [self setAutoresizes:NO]; } - (void)zoomImageToActualSize:(id)sender { [super zoomImageToActualSize:sender]; [self setFrame:NSZeroRect]; [self setAutoresizes:NO]; } - (void)zoomImageToFit:(id)sender { [self setAutoresizes:YES]; // instead of invoking super's zoomImageToFit: method, which has problems of its own, we invoke setAutoresizes:YES, which does the same thing, but also makes sure the image stays zoomed to fit even if the scroll view is resized, which is the most intuitive behavior, anyway. Since there are no scroll bars in autoresize mode, we need not add [self setFrame:NSZeroRect]. } - (void)setAutoresizes:(BOOL)autoresizes // As long as we autoresize, make sure that no scrollers flicker up occasionally during live update. { [self setHasHorizontalScroller:!autoresizes]; [self setHasVerticalScroller:!autoresizes]; [super setAutoresizes:autoresizes]; } @end </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload