Rotate UIImageView inside compass like iOS compass - rotation

I would like to include in my application a compass and labels cardinal gravitationally rotate and maintain its position as the compass of iOS application.
I've done some code and separately running, but when they work together goes crazy.
This is part of the code I use:
UIImageView * imgCompass;
UIImageView * north;
- (void)viewDidLoad
{
[super viewDidLoad];
locationManager = [[CLLocationManager alloc] init];
locationManager.delegate = self;
locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
locationManager.distanceFilter = kCLDistanceFilterNone;
locationManager.headingFilter = 1;
[locationManager requestWhenInUseAuthorization];
[locationManager startUpdatingLocation];
[locationManager startUpdatingHeading];
motionManager = [[CMMotionManager alloc] init];
motionManager.accelerometerUpdateInterval = 0.01;
motionManager.gyroUpdateInterval = 0.01;
[motionManager startAccelerometerUpdatesToQueue:[NSOperationQueue currentQueue]
withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {
if (!error) {
[self outputAccelertionData:accelerometerData.acceleration];
}
else{
NSLog(#"%#", error);
}
}];
}
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
// Convert Degree to Radian and move the needle
newRad = -newHeading.trueHeading * M_PI / 180.0f;
[UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.viewCompass.transform = CGAffineTransformMakeRotation(newRad);
} completion:nil];
}
- (void)outputAccelertionData:(CMAcceleration)acceleration{
//UIInterfaceOrientation orientationNew;
// Get the current device angle
float xx = -acceleration.x;
float yy = acceleration.y;
float angle = atan2(yy, xx);
[UIView animateWithDuration:0.2 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
// Add 1.5 to the angle to keep the image constantly horizontal to the viewer.
[self.north setTransform:CGAffineTransformMakeRotation(angle - 1.5)];
} completion:nil];
}
Any ideas? Thank You. I'm desperate...

I solved. Simply subtract the radius of the compass and add the result to the object you want. in my case north, east, west and south are UIImageView.
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
self.lblGrados.text = [NSString stringWithFormat:#"%.0f°", newHeading.magneticHeading];
// Convert Degree to Radian and move the needle
newRad = -newHeading.trueHeading * M_PI / 180.0f;
[UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
compassView.transform = CGAffineTransformMakeRotation(newRad);
} completion:nil];
[UIView animateWithDuration:0.6 delay:0 options:UIViewAnimationOptionCurveEaseOut animations:^{
[self.north setTransform:CGAffineTransformMakeRotation(-newRad)];
[self.south setTransform:CGAffineTransformMakeRotation(-newRad)];
[self.east setTransform:CGAffineTransformMakeRotation(-newRad)];
[self.west setTransform:CGAffineTransformMakeRotation(-newRad)];
} completion:nil];
}

Related

setNeedsDisplay not resulting in dirtyRect filling entire view

I am having a confusing issue. I try to draw a graph, and call setNeedsDisplay each time new data is added to the graph.
The graph receives new data via addData:(NSNotification*)theNote, which then tries several ways to call setNeedsDisplay to redraw the view. The data does not get redrawn properly, however, at this time. If I drag the window to another screen, or if I click on the graph and call setNeedsDisplay from mouseDown then the view is redrawn correctly. By monitoring the size of dirtyRect using NSLog, I have tracked the problem to a too small dirtyRect. But I cannot even guess how to correct this. Any ideas out there?
//
// graphView.m
// miniMRTOF
//
// Created by シューリ ピーター on 8/1/16.
// Copyright © 2016 シューリ ピーター. All rights reserved.
//
#import "graphView.h"
#implementation graphView
- (id)initWithFrame:(NSRect)frame{
self = [super initWithFrame:frame];
if (self) {
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:#selector(addData:) name:AddDataNotification object:nil];
theData = [[NSMutableArray alloc] init];
NSLog(#"graphView initialized");
}
return self;
}
-(void)addData:(NSNotification*)theNote{
NSLog(#"graphView has gotten the note");
NSMutableArray *theThermalArray = [[NSMutableArray alloc] init];
theThermalArray = [[theNote userInfo] objectForKey:#"theThermals"];
float ave = 0;
int n = 0;
for (int i=0; i<16; i++){
float f_i = [[theThermalArray objectAtIndex:i] floatValue];
ave += f_i;
if(f_i != 0) n++;
}
ave /= n;
[theData addObject:[NSNumber numberWithFloat:ave]];
NSLog(#"graphView has added %0.3f and now has %lu components", ave, (unsigned long)[theData count]);
[self setNeedsDisplay:YES];
[[self.window contentView] setNeedsDisplay:YES];
[self performSelectorOnMainThread:#selector(redraw) withObject:nil waitUntilDone:YES];
}
-(void)redraw{
[self setNeedsDisplay:YES];
[[self.window contentView] setNeedsDisplay:YES];
}
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
// Drawing code here.
NSLog(#"dirtyRect: x:%0.2f, y:%0.2f, w:%0.2f, h:%0.2f", dirtyRect.origin.x, dirtyRect.origin.y, dirtyRect.size.width, dirtyRect.size.height);
float xScale = ([self bounds].size.width)/((float)[theData count]+1e-3);//(maxX - minX);
float yScale = [self bounds].size.height/(maxT - minT);
[[NSColor whiteColor] set];
NSRect fillArea = [self bounds];
[NSBezierPath fillRect:fillArea];
if(dirtyRect.size.height < 100){
NSLog(#"small dirtyRect");
[[NSColor grayColor] set];
[NSBezierPath fillRect:dirtyRect];
}
dirtyRect = [self bounds];
int dataCount = (int)[theData count];
NSBezierPath *pathForFrame = [[NSBezierPath alloc] init];
NSPoint P0 = {1,1};
NSPoint P1 = {1, [self bounds].size.height};
NSPoint P2 = {[self bounds].size.width, 1};
[pathForFrame moveToPoint:P0];
[pathForFrame lineToPoint:P1];
[pathForFrame moveToPoint:P0];
[pathForFrame lineToPoint:P2];
[[NSColor redColor] set];
[pathForFrame stroke];
NSLog(#"drawing %i points", dataCount);
NSBezierPath *pathForPlot = [[NSBezierPath alloc] init];
if(dataCount<maxRawPlotData){
if(dataCount>1){
NSPoint p1;
p1.y = [[theData objectAtIndex:0] floatValue];
p1.x = (0-minX)*xScale;
p1.y = (p1.y-minT)*yScale;
[pathForPlot moveToPoint:p1];
NSLog(#"point: %0.1f, %0.1f", p1.x, p1.y);
}
for(int i=1; i<dataCount; i++){
NSPoint p;
p.y = [[theData objectAtIndex:i] floatValue];
p.x = (i-minX)*xScale;
p.y = (p.y-minT)*yScale;
[pathForPlot lineToPoint:p];
NSLog(#"point: %0.1f, %0.1f", p.x, p.y);
}
}
[[NSColor blackColor] set];
[pathForPlot stroke];
[txtMaxX setStringValue:[NSString stringWithFormat:#"%0.0f",maxX]];
}
-(void)controlTextDidEndEditing:(NSNotification *)obj{
NSLog(#"controlTextDidEndEditing");
if([[obj object] isEqualTo:txtMaxT]){
maxT = [txtMaxT floatValue];
[txtMidT setStringValue:[NSString stringWithFormat:#"%0.1f",0.5*(maxT+minT)]];
}
else if([[obj object] isEqualTo:txtMinT]){
minT = [txtMinT floatValue];
[txtMidT setStringValue:[NSString stringWithFormat:#"%0.1f",0.5*(maxT+minT)]];
}
else if([[obj object] isEqualTo:txtMaxX]){
maxX = [txtMaxX floatValue];
}
else if([[obj object] isEqualTo:txtMinX]){
minX = [txtMinX floatValue];
}
else NSLog(#"How'd we get here?");
[[[obj object] window] makeFirstResponder:[[obj object] window].contentView];
[self setNeedsDisplay:YES];
[self display];
}
-(void)mouseDown:(NSEvent *)theEvent{
NSLog(#"mousedown");
[self setNeedsDisplay:YES];
}
#end

GPUImageStillCamera image preview jumps when taking a photo

I am taking a square cropped photo with GPUImageStillCamera and allowing the user to zoom the camera. When the user clicks to take a picture the camera jumps forward for a split second (as if the camera zoomed in even further past the area the user zoomed to and then immediately returns to the correct crop once the image is returned to screen). This only happens when the user has zoomed the camera. If they have not zoomed the camera the flicker/jump does not happen. (The image return has the correct crop whether or not the user has zoomed).
Thoughts?
Creating camera and adding square crop
//Add in filters
stillCamera = [[GPUImageStillCamera alloc] initWithSessionPreset:AVCaptureSessionPreset1280x720 cameraPosition:AVCaptureDevicePositionBack];
stillCamera.outputImageOrientation = UIInterfaceOrientationPortrait;
//Creating a square crop filter
cropFilter = [[GPUImageCropFilter alloc] initWithCropRegion:CGRectMake(0.f, (720.0f/1280.0f)/2.0f, 1.f, (720.0f/1280.0f))];
Image zoom method
-(void)imagePinch:(UIPinchGestureRecognizer *)recognizer{ //Controlling the zoom scale as the user pinches the live preview
if (recognizer.state == UIGestureRecognizerStateBegan) {
zoomOutAdder = 0.0f;
if (currentScale > 2) {
zoomOutAdder = currentScale;
}
}
float addition = (recognizer.scale - lastScale);
if (addition > 0) {
addition = addition *1.7;
}
if (addition < 0) {
addition = addition *(1.7+zoomOutAdder);
}
currentScale = currentScale +addition;
lastScale = recognizer.scale;
if (currentScale < 1) {
currentScale = 1;
}
if (currentScale > 4) {
currentScale =4;
}
if (currentScale == 1) {
zoomOutAdder = 0.0f;
}
cameraImagePreview.transform = CGAffineTransformMakeScale(currentScale, currentScale);
if (recognizer.state == UIGestureRecognizerStateEnded) {
lastScale = 1.0f;
}
Take a photo method
//Adjust crop based on zoom scale of the user
CGFloat zoomReciprocal = 1.0f / currentScale;
CGPoint offset = CGPointMake(((1.0f - zoomReciprocal) / 2.0f), (((1.0f- zoomReciprocal)*(720.0f/1280.0f)) / 2.0f) + ((720.0f/1280.0f)/2)) ;
CGRect newCrop = cropFilter.cropRegion;
newCrop.origin.x = offset.x;
newCrop.origin.y = offset.y;
newCrop.size.width = cropFilter.cropRegion.size.width * zoomReciprocal;
newCrop.size.height = cropFilter.cropRegion.size.height *zoomReciprocal;
cropFilter.cropRegion = newCrop;
*/
//Place photo inside an image preview view for the user to decide if they want to keep it.
[stillCamera capturePhotoAsImageProcessedUpToFilter:cropFilter withOrientation:imageOrientation withCompletionHandler:^(UIImage *processedImage, NSError *error) {
//Pause the current camera
[stillCamera pauseCameraCapture];
//Rest of method
ADDED METHODS
- (void) flipCamera {
if (stillCamera.cameraPosition != AVCaptureDevicePositionFront) {
[UIView animateWithDuration:.65 animations:^{
flipCamera.transform = CGAffineTransformMakeScale(-1, 1);
}];
} else {
[UIView animateWithDuration:.65 animations:^{
flipCamera.transform = CGAffineTransformMakeScale(1, 1);
}];
}
[self performSelector:#selector(rotateCamera) withObject:0 afterDelay:.2];
}
- (void) rotateCamera {
[stillCamera rotateCamera];
//Adjust flash settings as needed
[stillCamera.inputCamera lockForConfiguration:nil];
if (stillCamera.cameraPosition != AVCaptureDevicePositionFront) {
[stillCamera.inputCamera setFlashMode:AVCaptureFlashModeOff];
}
NSAttributedString *attributedFlash =
[[NSAttributedString alloc]
initWithString:#"off"
attributes:
#{
NSFontAttributeName : [UIFont fontWithName:#"Roboto-Regular" size:13.0f],
NSForegroundColorAttributeName : [UIColor colorWithWhite:1 alpha:.55],
NSKernAttributeName : #(.25f)
}];
flashLabel.attributedText = attributedFlash;
[UIView animateWithDuration:.2 animations:^{
[flash setTintColor:[UIColor colorWithWhite:1 alpha:.55]];
}];
[stillCamera.inputCamera unlockForConfiguration];
}
- (void) changeFlash {
if (stillCamera.cameraPosition == AVCaptureDevicePositionFront) {//no flash available on front of camera
return;
}
[stillCamera.inputCamera lockForConfiguration:nil];
if (stillCamera.inputCamera.flashMode == AVCaptureFlashModeOff) {
[stillCamera.inputCamera setFlashMode:AVCaptureFlashModeOn];
[self animateFlashWithTintColor:[UIColor colorWithWhite:1 alpha:1] andString:#"on"];
} else if (stillCamera.inputCamera.flashMode == AVCaptureFlashModeOn) {
[stillCamera.inputCamera setFlashMode:AVCaptureFlashModeOff];
[self animateFlashWithTintColor:[UIColor colorWithWhite:1 alpha:.55] andString:#"off"];
}
[stillCamera.inputCamera unlockForConfiguration];
}
- (void) animateFlashWithTintColor:(UIColor *)color andString:(NSString *)text {
//Set new text
NSAttributedString *attributedFlash =
[[NSAttributedString alloc]
initWithString:text
attributes:
#{
NSFontAttributeName : [UIFont fontWithName:#"Roboto-Regular" size:13.0f],
NSForegroundColorAttributeName : [UIColor colorWithWhite:1 alpha:.55],
NSKernAttributeName : #(.25f)
}];
flashLabel.attributedText = attributedFlash;
float duration = .7;
[UIView animateKeyframesWithDuration:duration delay:0 options:0 animations:^{
[UIView addKeyframeWithRelativeStartTime:0 relativeDuration:duration animations:^{
[flash setTintColor:color];
}];
[UIView addKeyframeWithRelativeStartTime:0 relativeDuration:.7/duration animations:^{
flash.transform = CGAffineTransformMakeRotation(M_PI);
}];
}completion:^(BOOL finished){
flash.transform = CGAffineTransformIdentity;
}];
}
-(void) usePhoto {
if ([ALAssetsLibrary authorizationStatus] != ALAuthorizationStatusAuthorized){
NSLog(#"Do Not Have Right To Save to Photo Library");
}
//Save Image to Phone Album & save image
UIImageWriteToSavedPhotosAlbum(takenPhoto.image, nil, nil, nil);
//Save Image to Delegate
[self.delegate saveImageToDatabase:takenPhoto.image];
[self performSelector:#selector(dismissCamera) withObject:0 afterDelay:.4];
}
Some additional code showing the creation of the the various camera elements used to capture a photo.
centerPoint = CGPointMake(self.view.frame.size.width/2, (cameraHolder.frame.size.height+50+self.view.frame.size.height)/2);
cameraImagePreview = [[GPUImageView alloc] initWithFrame:CGRectMake(0, 0, cameraHolder.frame.size.width, cameraHolder.frame.size.width)];
[cameraHolder addSubview:cameraImagePreview];
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(imageTouch:)];
[cameraImagePreview addGestureRecognizer:tapGesture];
UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(imagePinch:)];
[cameraImagePreview addGestureRecognizer:pinchGesture];
float scaleForView = self.view.frame.size.width/720.0;
fullCameraFocusPoint = [[UIView alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width, 1280*scaleForView)];
fullCameraFocusPoint.center = CGPointMake(cameraHolder.frame.size.width/2, (cameraHolder.frame.size.width/2)+50);
[self.view insertSubview:fullCameraFocusPoint atIndex:0];
takenPhoto = [[UIImageView alloc]initWithFrame:cameraHolder.frame];
takenPhoto.alpha = 0;
[self.view addSubview:takenPhoto];
//Add in filters
stillCamera = [[GPUImageStillCamera alloc] initWithSessionPreset:AVCaptureSessionPreset1280x720 cameraPosition:AVCaptureDevicePositionBack];
stillCamera.outputImageOrientation = UIInterfaceOrientationPortrait;
//Creating a square crop filter
cropFilter = [[GPUImageCropFilter alloc] initWithCropRegion:CGRectMake(0.f, (720.0f/1280.0f)/2.0f, 1.f, (720.0f/1280.0f))];
//Create standard vignette filter
vignetteFilter = [[GPUImageVignetteFilter alloc] init]; //1
vignetteFilter.vignetteCenter = CGPointMake(.5, .5);
vignetteFilter.vignetteStart = 0.4f;
vignetteFilter.vignetteEnd = 1.08f;
//Add filters to photo
[cropFilter addTarget:vignetteFilter];
[stillCamera addTarget:cropFilter];
[vignetteFilter addTarget:cameraImagePreview];
[stillCamera startCameraCapture];

Animation Delay

I am trying to set a delay for my animation, so once it appears and then disappears, I want to wait a certain amount of seconds for it to reappear. I have tried placing it in multiple spots throughout my code, but it was all the same result.
- (void) startRedDot {
redDotTimer = [NSTimer scheduledTimerWithTimeInterval:1.5
target:self
selector:#selector(moveButtonWithAnimation)
userInfo:nil
repeats:YES];
[redDotTimer fire];
}
-(void) moveButtonRandomly {
CGSize limits;
CGPoint newPosition;
// Get limits
limits.width = gameView.frame.size.width - redButton.frame.size.width;
limits.height = gameView.frame.size.height - redButton.frame.size.height;
// Calculate new Position
newPosition = (CGPoint){ limits.width * drand48(), limits.height * drand48() };
// Set new frame
redButton.frame = (CGRect){ newPosition, redButton.frame.size };
}
- (void) moveButtonWithAnimation {
CGFloat fadeDurration;
if ( !redButton )
return; // only invoke the button if it exists
fadeDurration = 0.0f;
//Fade Out
[UIView animateWithDuration: fadeDurration animations:^{
redButton.alpha = 0.0f;
} completion:^(BOOL finished) {
// Move the button while it is not visible
[self moveButtonRandomly];
[UIView setAnimationDelay:9.0];
// Fade in
[UIView animateWithDuration: fadeDurration animations:^{
redButton.alpha = 4.0f;
}];
}];
}
setAnimationDelay should use in beginAnimation and commitAnimation block, and it was old way to do animation in iOS. In your case try this:
- (void) moveButtonWithAnimation {
CGFloat fadeDurration;
if ( !redButton )
return; // only invoke the button if it exists
fadeDurration = 2.0f;
//Fade Out
[UIView animateWithDuration: fadeDurration animations:^{
redButton.alpha = 0.0f;
} completion:^(BOOL finished) {
// Move the button while it is not visible
[self moveButtonRandomly];
[UIView animateWithDuration:fadeDurration delay:2.0 options:0 animations:^{
redButton.alpha = 1.0f;
} completion:nil];
}];
}

NSWindow flip animation (easy and universal)

How to make flip animation for OS X application windows without complex coding?
Finally, I did it. I have created object that work with NSWindowController objects instead of NSWidows.
ALWindowFlipAnimator.h
#import <Foundation/Foundation.h>
//............................................................................................................
// Shorten macroes:
#define FLIPANIMATOR [ALWindowFlipAnimator sharedWindowFlipAnimator]
//............................................................................................................
// Window flip direction:
typedef NS_ENUM(NSUInteger, ALFlipDirection)
{
ALFlipDirectionLeft,
ALFlipDirectionRight,
ALFlipDirectionUp,
ALFlipDirectionDown
};
#interface ALWindowFlipAnimator : NSObject
+(ALWindowFlipAnimator *)sharedWindowFlipAnimator;
-(void)flipToWindowNibName:(NSString *)nibName direction:(ALFlipDirection)direction;
#end
ALWindowFlipAnimator.m
#import "ALWindowFlipAnimator.h"
#import <QuartzCore/QuartzCore.h>
#implementation ALWindowFlipAnimator
{
NSWindowController *_currentWindowController; // Current window controller
NSWindowController *_nextWindowController; // Next window controller to flip to
NSWindow *_animationWindow; // Window where flip animation plays
}
//============================================================================================================
// Initialize flip window controller
//============================================================================================================
-(id)init
{
self = [super init];
if (self)
{
_currentWindowController = nil;
_nextWindowController = nil;
_animationWindow = nil;
}
return self;
}
//============================================================================================================
// Create shared flip window manager
//============================================================================================================
+(ALWindowFlipAnimator *)sharedWindowFlipAnimator
{
static ALWindowFlipAnimator *wfa = nil;
if (!wfa) wfa = [[ALWindowFlipAnimator alloc] init];
return wfa;
}
//============================================================================================================
// Flip to window with selected NIB file name from the current one
//============================================================================================================
-(void)flipToWindowNibName:(NSString *)nibName direction:(ALFlipDirection)direction
{
if (!_currentWindowController || ![[_currentWindowController window] isVisible])
{
// No current window controller or window is closed
_currentWindowController = [[NSClassFromString(nibName) alloc] initWithWindowNibName:nibName];
[_currentWindowController showWindow:self];
}
else
{
if ([[_currentWindowController className] isEqualToString:nibName])
// Bring current window to front
[[_currentWindowController window] makeKeyAndOrderFront:self];
else
{
// Flip to new window
_nextWindowController = [[NSClassFromString(nibName) alloc] initWithWindowNibName:nibName];
[self flipToNextWindowControllerDirection:direction];
}
}
}
#pragma mark - Flip animation
#define DEF_DURATION 2.0 // Animation duration
#define DEF_SCALE 1.2 // Scaling factor for animation window (_animationWindow)
//============================================================================================================
// Start window flipping animation
//============================================================================================================
-(void)flipToNextWindowControllerDirection:(ALFlipDirection)direction
{
NSWindow *currentWindow = [_currentWindowController window];
NSWindow *nextWindow = [_nextWindowController window];
NSView *currentWindowView = [currentWindow.contentView superview];
NSView *nextWindowView = [nextWindow.contentView superview];
// Create window for animation
CGFloat maxWidth = MAX(currentWindow.frame.size.width, nextWindow.frame.size.width);
CGFloat maxHeight = MAX(currentWindow.frame.size.height, nextWindow.frame.size.height);
CGFloat xscale = DEF_SCALE * 2.0;
maxWidth += maxWidth * xscale;
maxHeight += maxHeight * xscale;
CGRect animationFrame = CGRectMake(NSMidX(currentWindow.frame) - (maxWidth / 2),
NSMidY(currentWindow.frame) - (maxHeight / 2),
maxWidth, maxHeight);
_animationWindow = [[NSWindow alloc] initWithContentRect:NSRectFromCGRect(animationFrame)
styleMask:NSBorderlessWindowMask
backing:NSBackingStoreBuffered
defer:NO];
[_animationWindow setOpaque:NO];
[_animationWindow setHasShadow:NO];
[_animationWindow setBackgroundColor:[NSColor clearColor]];
[_animationWindow.contentView setWantsLayer:YES];
[_animationWindow setLevel:NSScreenSaverWindowLevel];
// Move next window closer to the current one
CGRect nextFrame = CGRectMake(NSMidX(currentWindow.frame) - (NSWidth(nextWindow.frame) / 2 ),
NSMaxY(currentWindow.frame) - NSHeight(nextWindow.frame),
NSWidth(nextWindow.frame), NSHeight(nextWindow.frame));
[nextWindow setFrame:NSRectFromCGRect(nextFrame) display:NO];
// Make snapshots of current and next windows
[CATransaction begin];
CALayer *currentWindowSnapshot = [self snapshotToImageLayerFromView:currentWindowView];
CALayer *nextWindowSnapshot = [self snapshotToImageLayerFromView:nextWindowView];
[CATransaction commit];
currentWindowSnapshot.frame = [self rect:currentWindowView.frame
fromView:currentWindowView
toView:[_animationWindow contentView]];
nextWindowSnapshot.frame = [self rect:nextWindowView.frame
fromView:nextWindowView
toView:[_animationWindow contentView]];
// Create 3D transform matrix to snapshots
CATransform3D transform = CATransform3DIdentity;
transform.m34 = -(1.0 / 1500.0);
currentWindowSnapshot.transform = transform;
nextWindowSnapshot.transform = transform;
// Add snapshots to animation window
[CATransaction begin];
[[_animationWindow.contentView layer] addSublayer:currentWindowSnapshot];
[[_animationWindow.contentView layer] addSublayer:nextWindowSnapshot];
[CATransaction commit];
[_animationWindow makeKeyAndOrderFront:nil];
// Animation for snapshots
[CATransaction begin];
CAAnimation *currentSnapshotAnimation = [self animationWithDuration:(DEF_DURATION * 0.5) flip:YES direction:direction];
CAAnimation *nextSnapshotAnimation = [self animationWithDuration:(DEF_DURATION * 0.5) flip:NO direction:direction];
[CATransaction commit];
// Start animation
nextSnapshotAnimation.delegate = self;
[currentWindow orderOut:nil];
[CATransaction begin];
[currentWindowSnapshot addAnimation:currentSnapshotAnimation forKey:#"flipAnimation"];
[nextWindowSnapshot addAnimation:nextSnapshotAnimation forKey:#"flipAnimation"];
[CATransaction commit];
}
//============================================================================================================
// Convert rectangle from one view coordinates to another
//============================================================================================================
-(CGRect)rect:(NSRect)rect fromView:(NSView *)fromView toView:(NSView *)toView
{
rect = [fromView convertRect:rect toView:nil];
rect = [fromView.window convertRectToScreen:rect];
rect = [toView.window convertRectFromScreen:rect];
rect = [toView convertRect:rect fromView:nil];
return NSRectToCGRect(rect);
}
//============================================================================================================
// Get snapshot of selected view as layer with bitmap image
//============================================================================================================
-(CALayer *)snapshotToImageLayerFromView:(NSView*)view
{
// Make view snapshot
NSBitmapImageRep *snapshot = [view bitmapImageRepForCachingDisplayInRect:view.bounds];
[view cacheDisplayInRect:view.bounds toBitmapImageRep:snapshot];
// Convert snapshot to layer
CALayer *layer = [CALayer layer];
layer.contents = (id)snapshot.CGImage;
layer.doubleSided = NO;
// Add shadow of window to snapshot
[layer setShadowOpacity:0.5];
[layer setShadowOffset:CGSizeMake(0.0, -10.0)];
[layer setShadowRadius:15.0];
return layer;
}
//============================================================================================================
// Create animation
//============================================================================================================
-(CAAnimation *)animationWithDuration:(CGFloat)time flip:(BOOL)flip direction:(ALFlipDirection)direction
{
// Set flip direction
NSString *keyPath = #"transform.rotation.y";
if (direction == ALFlipDirectionUp || direction == ALFlipDirectionDown) keyPath = #"transform.rotation.x";
CABasicAnimation *flipAnimation = [CABasicAnimation animationWithKeyPath:keyPath];
CGFloat startValue = flip ? 0.0 : -M_PI;
CGFloat endValue = flip ? M_PI : 0.0;
if (direction == ALFlipDirectionLeft || direction == ALFlipDirectionUp)
{
startValue = flip ? 0.0 : M_PI;
endValue = flip ? -M_PI : 0.0;
}
flipAnimation.fromValue = [NSNumber numberWithDouble:startValue];
flipAnimation.toValue = [NSNumber numberWithDouble:endValue];
CABasicAnimation *scaleAnimation = [CABasicAnimation animationWithKeyPath:#"transform.scale"];
scaleAnimation.toValue = [NSNumber numberWithFloat:DEF_SCALE];
scaleAnimation.duration = time * 0.5;
scaleAnimation.autoreverses = YES;
CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
animationGroup.animations = [NSArray arrayWithObjects:flipAnimation, scaleAnimation, nil];
animationGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animationGroup.duration = time;
animationGroup.fillMode = kCAFillModeForwards;
animationGroup.removedOnCompletion = NO;
return animationGroup;
}
//============================================================================================================
// Flip animation did finish
//============================================================================================================
-(void)animationDidStop:(CAAnimation *)animation finished:(BOOL)flag
{
[[_nextWindowController window] makeKeyAndOrderFront:nil];
[_animationWindow orderOut:nil];
_animationWindow = nil;
_currentWindowController = _nextWindowController;
}
#end
How to use:
Create some new NSWindowController objects with NIBs in your project
Call [FLIPANIMATOR flipToWindowNibName:#"SecondWindowController" direction:ALFlipDirectionRight]; to flip to second window, or [FLIPANIMATOR flipToWindowNibName:#"FirstWindowController" direction:ALFlipDirectionLeft]; to return back
Link QuarzCore.framework to your project
That's all!

UITouch Event on Animated UIImagevIew

I am using the Snowfall sample code which drops UImages from the top of the screen. I want to detect a Touch on the UIImageview and update a label. If i create a single UIImageView in IBOutlet and connect it to the touch event the label is updated correctly. But when I try to apply it to the falling UIImageView it does not work. Here is what I have so far:
- (void)viewDidLoad {
[super viewDidLoad];
score = 0;
self.view.backgroundColor = [UIColor colorWithRed:0.5 green:0.5 blue:1.0 alpha:1.0];
flakeImage = [UIImage imageNamed:#"flake.png"];
[NSTimer scheduledTimerWithTimeInterval:(0.5) target:self selector:#selector(onTimer) userInfo:nil repeats:YES];
}
- (void)onTimer
{
flakeView = [[UIImageView alloc] initWithImage:flakeImage];
flakeView.opaque = YES;
flakeView.userInteractionEnabled = YES;
flakeView.multipleTouchEnabled = YES;
int startX = round(random() % 320);
int endX = round(random() % 320);
double scale = 1 / round(random() % 100) + 1.0;
double speed = 1 / round(random() % 100) + 1.0;
flakeView.frame = CGRectMake(startX, -100.0, 25.0 * scale, 25.0 * scale);
[self.view addSubview:flakeView];
[self.view bringSubviewToFront:flakeView];
[UIView beginAnimations:nil context:flakeView];
[UIView setAnimationDuration:5 * speed];
flakeView.frame = CGRectMake(endX, 500.0, 25.0 * scale, 25.0 * scale);
[UIView setAnimationDidStopSelector:#selector(onAnimationComplete:finished:context:)];
[UIView setAnimationDelegate:self];
[UIView commitAnimations];
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
if ([touch view] == flakeView)
{
NSLog(#"tag %#",touch);
score = score + 1;
lbl1.text = [NSString stringWithFormat:#"%i", score];
}
}
Animations typically disable touch handling so you have to use:
animateWithDuration:delay:options:animations:completion
to set the options to receive touches.
http://developer.apple.com/library/IOs/#documentation/WindowsViews/Conceptual/ViewPG_iPhoneOS/AnimatingViews/AnimatingViews.html#//apple_ref/doc/uid/TP40009503-CH6-SW1
IIRC the option you want is: UIViewAnimationOptionAllowUserInteraction Look for UIViewAnimationOptions in the above doc for the full list.

Resources