Перевернуть изображение NSButton вверх ногами

У меня очень простое приложение для macOS (написано на Swift с использованием Xcode 8.2.1). В моем основном пользовательском интерфейсе есть NSButton с пользовательским изображением (оно представляет собой игральную карту, как в покере). Когда я нажимаю эту кнопку, я хочу, чтобы ее изображение было повернуто на 180 градусов (перевернуто вверх дном).

Я новичок в аффинных преобразованиях, но я подумал, что это может сработать (это не так).

@IBAction func buttonClicked(_ sender: NSButton) {
  var transform = sender.layer?.affineTransform()
  transform = transform?.rotated(by:  180.0 * (CGFloat.pi / 180))
  sender.layer?.setAffineTransform(transform!)
}

Карта поворачивается правильно, но рисуется в новом месте.

Как правильно повернуть изображение кнопки на 180 градусов, сохраняя при этом его положение в родительском статике?


person RobertJoseph    schedule 07.02.2017    source источник
comment
Вы добавили ограничения на свою кнопку?   -  person AaoIi    schedule 07.02.2017
comment
Ограничений нет, авто-макет отключен.   -  person RobertJoseph    schedule 07.02.2017
comment
Проверьте мой ответ :)   -  person AaoIi    schedule 08.02.2017


Ответы (2)


Чтобы повернуть изображение NSImage или NSButton, я написал расширение для NSImage, используя Swift 3.

Вы можете перейти к функции:

  • Угол поворота скажем 180 градусов.
  • Желаемое изображение для поворота.

Вот как это можно назвать:

@IBAction func button(_ sender: NSButton) {

     sender.image = NSImage().imageRotatedByDegrees(rotationDegree: 180,
forImage: sender.image!)

}

И ваше расширение:

extension NSImage {

     func imageRotatedByDegrees(rotationDegree degrees:CGFloat,forImage
image:NSImage) -> NSImage {

         // calculate the bounds for the rotated image
         var imageBounds = NSRect(origin: NSZeroPoint, size: image.size)

         let boundsPath : NSBezierPath = NSBezierPath(rect: imageBounds)

         var transform : NSAffineTransform = NSAffineTransform()

         transform.rotate(byDegrees: degrees)
         boundsPath.transform(using: transform as AffineTransform)

         let rotatedBounds : NSRect = NSRect(origin: NSZeroPoint, size:
boundsPath.bounds.size)

         let rotatedImage = NSImage(size: rotatedBounds.size)

         // center the image within the rotated bounds

         imageBounds.origin.x = NSMidX(rotatedBounds) - (NSWidth
(imageBounds) / 2); imageBounds.origin.y = NSMidY(rotatedBounds) -
(NSHeight (imageBounds) / 2)

         // set up the rotation transform
         transform = NSAffineTransform()

         transform.translateX(by: +(NSWidth(rotatedBounds) / 2), yBy:
+(NSHeight(rotatedBounds) / 2))

         transform.rotate(byDegrees: degrees)

         transform.translateX(by: -(NSWidth(rotatedBounds) / 2), yBy:
-(NSHeight(rotatedBounds) / 2))

         // draw the original image, rotated, into the new image
         rotatedImage.lockFocus()
         transform.concat()

         image.draw(in: imageBounds, from: NSZeroRect, operation:
NSCompositeCopy, fraction: 1.0)

         rotatedImage.unlockFocus()

         return rotatedImage

     }

}
person AaoIi    schedule 08.02.2017
comment
Спасибо @Aaoli! Единственная проблема возникает, когда вы устанавливаете градусы поворота примерно на 15. Каждое последующее вращение делает изображение все меньше и меньше. - person RobertJoseph; 08.02.2017
comment
@RobertJoseph, я проверю :) - person AaoIi; 08.02.2017

Вы должны использовать преобразование перевода, чтобы перевести центр в 0,0, а затем повернуть, а затем перевести обратно, чтобы центр находился там, где вы хотите. Что-то типа:

 transform = transform?
     .translatedBy(x: -self.center.x, y: -self.center.y)
     .rotated(by:  180.0 * (CGFloat.pi / 180))
     .translatedBy(x: self.center.x, y: self.center.y)
person Lou Franco    schedule 07.02.2017
comment
Спасибо. Что означает self в вашем примере? Будет ли это sender в моем примере? Кроме того, NSView не имеет свойства center. - person RobertJoseph; 07.02.2017
comment
@RobertJoseph, вероятно, это ваш sender.layer :) - person AaoIi; 07.02.2017
comment
@AaoIi Спасибо, но у CALayer тоже нет свойства center (по крайней мере, в macOS). - person RobertJoseph; 07.02.2017
comment
@RobertJoseph, тогда, вероятно, отправитель является кнопкой. - person AaoIi; 07.02.2017
comment
@AaoIi sender (NSButton) также не имеет свойства center. В iOS UIView имеет свойство center. Этого нет в NSView или CALayer в macOS. - person RobertJoseph; 07.02.2017
comment
@RobertJoseph Я вижу, я посмотрю на это и вернусь к вам - person AaoIi; 07.02.2017
comment
Вот мой код контроллера представления. Изображение для кнопки было задано в раскадровке. - person RobertJoseph; 07.02.2017
comment
@RobertJoseph Я вижу, что вы вычисляете центр, так это сработало или у вас возникла проблема? - person AaoIi; 07.02.2017
comment
@AaoIi Нет, это не работает. Изображение кнопки исчезает, пока я не изменю размер окна (и даже тогда изображение остается в исходной ориентации). - person RobertJoseph; 07.02.2017