Continuous Rotation of Nsimageview (So It Appears to Be Animated)

Continuous Rotation of NSImageView (so it appears to be animated)

You could add an extension of UIView or UIImageView like this:

extension UIView {

///The less is the timeToRotate, the more fast the animation is !
func spinClockwise(timeToRotate: Double) {
startRotate(CGFloat(M_PI_2), timeToRotate: timeToRotate)
}

///The less is the timeToRotate, the more fast the animation is !
func spinAntiClockwise(timeToRotate: Double) {
startRotate(CGFloat(-M_PI_2), timeToRotate: timeToRotate)
}

func startRotate(angle: CGFloat, timeToRotate: Double) {
UIView.animateWithDuration(timeToRotate, delay: 0.0, options:[UIViewAnimationOptions.CurveLinear, UIViewAnimationOptions.Repeat], animations: {
self.transform = CGAffineTransformMakeRotation(angle)
}, completion: nil)
print("Start rotating")
}

func stopAnimations() {
self.layer.removeAllAnimations()
print("Stop rotating")
}
}

So when you want to rotate your myImg, you just have to call:

myImg.spinClockwise(3)

And when you want to stop it:

myImg.stopAnimations()

NOTE:
I added a playground just so you can test it out ;)

Cheers!

EDIT:

My bad, Here is the example for NSView:

extension NSView {

///The less is the timeToRotate, the more fast the animation is !
func spinClockwise(timeToRotate: Double) {
startRotate(CGFloat(-1 * M_PI * 2.0), timeToRotate: timeToRotate)
}

///The less is the timeToRotate, the more fast the animation is !
func spinAntiClockwise(timeToRotate: Double) {
startRotate(CGFloat(M_PI * 2.0), timeToRotate: timeToRotate)
}

func startRotate(angle: CGFloat, timeToRotate: Double) {

let rotateAnimation = CABasicAnimation(keyPath: "transform.rotation")
rotateAnimation.fromValue = 0.0
rotateAnimation.toValue = angle
rotateAnimation.duration = timeToRotate
rotateAnimation.repeatCount = .infinity

self.layer?.addAnimation(rotateAnimation, forKey: nil)

Swift.print("Start rotating")
}

func stopAnimations() {
self.layer?.removeAllAnimations()
Swift.print("Stop rotating")
}
}

Important note: Now, after my tests, I noticed that you must set the anchor point of your NSView in the middle so that it can rotate around its center:

view.layer?.anchorPoint = CGPointMake(0.5, 0.5)

I added a new playground with the OSX example

How do I achieve continuous rotation of an NSImage inside NSImageView?

Getting an object to rotate more than 180 degrees is actually a little bit tricky. The problem is that you specify a transformation matrix for the ending rotation, and the system decides to rotate in the other direction.

What I've done is to create a CABasicAnimation of less than 180 degrees, set up to be additive , and with a repeat count. Each step in the animation animates the object more.

The following code is taken from an iOS application, but the technique is identical in Mac OS.

  CABasicAnimation* rotate =  [CABasicAnimation animationWithKeyPath: @"transform.rotation.z"];
rotate.removedOnCompletion = FALSE;
rotate.fillMode = kCAFillModeForwards;

//Do a series of 5 quarter turns for a total of a 1.25 turns
//(2PI is a full turn, so pi/2 is a quarter turn)
[rotate setToValue: [NSNumber numberWithFloat: -M_PI / 2]];
rotate.repeatCount = 11;

rotate.duration = duration/2;
rotate.beginTime = start;
rotate.cumulative = TRUE;
rotate.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];

CAAnimation objects operate on layers, so for Mac OS, you'll need to set the "wants layer" property in interface builder, and then add the animation to your view's layer.

To make your view rotate forever, you'd set repeat count to some very large number like 1e100.

Once you've created your animation, you'd add it to your view's layer with code something like this:

[myView.layer addAnimation: rotate forKey: @"rotateAnimation"];

That's about all there is to it.

Rotate NSImageView at its Center to Make it Spin

I just created a simple demo which contains the handy setAnchorPoint extension for all views.

The main reason you see your rotation from a corner is that your anchor point is somehow reset to 0,0.

import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

@IBOutlet weak var window: NSWindow!
var imageView: NSImageView!

func applicationDidFinishLaunching(_ aNotification: Notification) {
// Insert code here to initialize your application

// Create red NSImageView
imageView = NSImageView(frame: NSRect(x: 100, y: 100, width: 100, height: 100))
imageView.wantsLayer = true
imageView.layer?.backgroundColor = NSColor.red.cgColor

window.contentView?.addSubview(imageView)
}

func applicationWillTerminate(_ aNotification: Notification) {
// Insert code here to tear down your application
}

func applicationDidBecomeActive(_ notification: Notification) {
// Before animate, reset the anchor point
imageView.setAnchorPoint(anchorPoint: CGPoint(x: 0.5, y: 0.5))
// Start animation
if imageView.layer?.animationKeys()?.count == 0 || imageView.layer?.animationKeys() == nil {
let rotate = CABasicAnimation(keyPath: "transform.rotation")
rotate.fromValue = 0
rotate.toValue = CGFloat(-1 * .pi * 2.0)
rotate.duration = 2
rotate.repeatCount = Float.infinity

imageView.layer?.add(rotate, forKey: "rotation")
}
}
}

extension NSView {
func setAnchorPoint(anchorPoint:CGPoint) {
if let layer = self.layer {
var newPoint = NSPoint(x: self.bounds.size.width * anchorPoint.x, y: self.bounds.size.height * anchorPoint.y)
var oldPoint = NSPoint(x: self.bounds.size.width * layer.anchorPoint.x, y: self.bounds.size.height * layer.anchorPoint.y)

newPoint = newPoint.applying(layer.affineTransform())
oldPoint = oldPoint.applying(layer.affineTransform())

var position = layer.position

position.x -= oldPoint.x
position.x += newPoint.x

position.y -= oldPoint.y
position.y += newPoint.y

layer.anchorPoint = anchorPoint
layer.position = position
}
}
}

Sample Image

Animate NSImageView translation

If you are using auto layout you can add an outlet to one of your constraints and change the constant value through the animator.

Example

Here I have a view with a label and a button

My view

The label has two constraints.

  • It is centred horizontally in the view
  • It has a distance of 80 to the bottom of the view

I can now find the "distance to bottom" outlet in the Document Outline

this guy

And ctrl drag it to my corresponding NSViewController where I create an outlet for it.

@IBOutlet weak var distanceToBottom: NSLayoutConstraint!

I can verify that the outlet is set by looking at the Connections Inspector in the right side of the screen

Sample Image

Last step is to animate the view. Here I'm just using an IBAction on a NSButton like so:

@IBAction func animate(_ sender: NSButton) {
distanceToBottom.animator().constant = 5
}

If I run that my label animates nicely to its new position 5 pixels from the bottom.

final result

Hope that helps you.

CoreAnimation setFrameCenterRotation Doesn't Animate Properly

First make sure NSView layer backed (Core Animation enabled), animator proxy would otherwise animate without CA. Do this with -setWantsLayer:YES, or by checking the corresponding option for that view in IB.

Second, set the layer anchor point to 0.5, 0.5:

view.layer.anchorPoint = CGPointMake(0.5,0.5);

Third, you may need direct layer interaction if you can't get what you want, but first try with AppKit API's, as it preserves mouse events, etc.

NSImage rotation in NSView is not working

For any future visitors, The code works perfectly and you may use it if you want except make sure before you add layer inside nsview we have to set that nsview wants layer.

so, the changes will be...



- (void)awakeFromNib {

NSImage *image = [NSImage imageNamed:@"SyncRing.png"];
//init layer
syncFirst = [CALayer layer];

//animatated content size init
syncFirst.bounds = CGRectMake(0, 0, image.size.width, image.size.height);
syncFirst.position = CGPointMake(10, 10);
syncFirst.contents = (id)[self convertToCGImageFromNasImage:image];

/*HERE SETWANTSLAYER TO TRUE IN ORDER TO FIX*/
[nsview setWantsLayer:YES];

[nsview.layer addSublayer:syncFirst];
}


Before using this code

Please refer to the discussion in comment. There are some useful tips, Which I have overlooked while solving my problem. Credit goes to - Peter Hosey



Related Topics



Leave a reply



Submit