将NSFinineTransform应用于NSView



我想对NSView子类进行两次简单的转换,以便在X轴、Y轴或两者上翻转它。我是一个经验丰富的iOS开发人员,但我不知道如何在macOS中做到这一点。我已经创建了一个具有所需翻译和比例的NSFinineTransform,但无法确定如何将其实际应用于NSView。我能找到的唯一可以接受任何类型转换的属性是[[NSView layer] transform],但这需要CATransform3D。

我唯一的成功是在NSImageView中使用转换来翻转图像,方法是在新的空NSImage上调用lockFocus,创建转换,然后在锁定的图像中绘制未翻转的图像。然而,这远远不能令人满意,因为它不处理任何子视图,并且可能比直接将变换应用于NSView/NSImageView更昂贵。

这就是解决方案:

- (void)setXScaleFactor:(CGFloat)xScaleFactor {
_xScaleFactor = xScaleFactor;
[self setNeedsDisplay];
}
- (void)setYScaleFactor:(CGFloat)yScaleFactor {
_yScaleFactor = yScaleFactor;
[self setNeedsDisplay];
}
- (void)drawRect:(NSRect)dirtyRect {
NSAffineTransform *transform = [[NSAffineTransform alloc] init];
[transform scaleXBy:self.xScaleFactor yBy:self.yScaleFactor];
[transform set];
[super drawRect:dirtyRect];
}

感谢l'l'l提供的有关使用NSGraphicsContext的提示。

我简直不敢相信,在AppKit中简单地水平翻转图像之前,我必须进行了多少小时的搜索和实验。我对这个问题和马什的回答再怎么支持也不为过。

这是我的解决方案的更新版本,用于swift水平翻转图像。该方法在NSImageView子类中实现。

override func draw(_ dirtyRect: NSRect) {
// NSViews are not backed by CALayer by default in AppKit. Must request a layer
self.wantsLayer = true
if self.flippedHoriz {
// If a horizontal flip is desired, first multiple every X coordinate by -1. This flips the image, but does it around the origin (lower left), not the center
var trans = AffineTransform(scaledByX: -1, byY: 1)
// Add a transform that moves the image by the width so that its lower left is at the origin
trans.append(AffineTransform(translationByX: self.frame.size.width, byY: 0)
// AffineTransform is bridged to NSAffineTransform, but it seems only NSAffineTransform has the set() and concat() methods, so convert it and add the transform to the current graphics context
(trans as NSAffineTransform).concat()
}
// Don't be fooled by the Xcode placehoder. This must be *after* the above code
super.draw(dirtyRect)
}

转换的行为也需要一些实验才能理解。NSAffineTransform.set()的帮助说明:

it removes the existing transformation matrix, which is an accumulation of transformation matrices for the screen, window, and any superviews.

这很可能会破坏某些东西。由于我仍然希望尊重窗口和超视图应用的所有转换,因此concat()方法更合适。

concat()将现有变换矩阵乘以自定义变换。不过,这并不完全是累积的。每次调用draw时,变换都会应用于视图的原始变换。因此,反复调用draw并不会持续翻转图像。因此,为了不翻转图像,只需不应用变换即可。

相关内容

  • 没有找到相关文章

最新更新