Применить NSAffineTransform к NSView
Я хочу сделать пару простых преобразований в подклассе NSView, чтобы перевернуть его по оси X, оси Y или обоим. Я опытный разработчик iOS, но я просто не могу понять, как это сделать в macOS. Я создал NSAffineTransform с необходимыми переводами и масштабами, но не могу определить, как на самом деле применить это к NSView. Единственное свойство, которое я могу найти, которое принимает любое преобразование, это [[NSView layer] transform]
, но для этого требуется CATransform3D.
Единственный успех, который у меня был, - это использование преобразования, чтобы перевернуть изображение, если NSImageView, вызвав lockFocus
на новый, пустой NSImage
, создавая преобразование, затем рисуя неперекрытое изображение внутри заблокированного изображения. Однако это далеко не удовлетворительно, поскольку оно не обрабатывает какие-либо подпредставления и, по-видимому, более затратно, чем применение преобразования непосредственно к NSView
/NSImageView
,
2 ответа
Это было решение:
- (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. Я не могу проголосовать за этот вопрос и ответить достаточно.
Вот обновленная версия моего решения для быстрого переворота изображения по горизонтали. Этот метод реализован в
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)
}
Чтобы понять поведение преобразований, также потребовалось немного экспериментов. Помощь для
it removes the existing transformation matrix, which is an accumulation of transformation matrices for the screen, window, and any superviews.
Это, скорее всего, что-то сломает . Поскольку я хотел по-прежнему уважать все преобразования, применяемые окном и суперпредставлениями, этот метод более уместен.