我有一个Mac App已经在应用商店中待了一年左右。它最初与目标SDK 10.7 Lion一起发布。升级到Mountain Lion后,它不再起作用。

该应用程序在NSImageView中嵌入的IKImageView中显示大图像。将其放入滚动视图的目的是使两个手指可以拖动工作,而不是用户必须单击即可拖动。使用Nicholas Riley的ScrollViewWorkaround,我可以使用两根手指滚动显示用户放大后显示的剪辑内容。就像在“预览”应用程序中看到的那样。

尼古拉斯·莱利的解决方案:
IKImageView and scroll bars

现在在Mountain Lion中这是行不通的。放大,缩小或缩放按钮后,图像被锁定在图像的左下方。它不会滚动。

所以问题是,在IKImageView中显示大图像并用两根手指拖动缩放图像的合适方法是什么?

谢谢,
有状态的

最佳答案

好吧,尼古拉斯·莱利(Nicholas Riley)的解决方案很丑陋,因为它可以解决错误的课程;问题不在于NSClipView(他将其子类化,但可以正常使用),而在于IKImageView。

IKImageView的问题实际上非常简单(上帝知道为什么苹果没有在什么情况下解决此问题?……7年……):IKImageView的大小无法适应其显示图像的大小。现在,当您将IKImageView嵌入到NSScrollView中时,滚动视图显然只能相对于嵌入式IKImageView的大小而不是相对于其包含的图像来调整其滚动条。并且由于IKImageView的大小始终保持不变,因此滚动条将无法按预期工作。

以下代码子类化IKImageView并解决了此问题。 las,一旦缩放,它就无法解决IKImageView在Mountain Lion中容易崩溃的事实……

///////////////////// HEADER FILE - FixedIKImageView.h

#import <Quartz/Quartz.h>

@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 < clipViewSize.width)?  clipViewSize.width : imageSize.width * zoomFactor;
        CGFloat newHeight = (imageSize.height * zoomFactor < 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

关于macos - 在Mountain Lion中使用IKImageView和NSScrollView进行两指拖动,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/12231573/

10-10 16:07