I am attempting to draw this plane with Core Animation in OS X:
(without the black background, however).
This is the code in my custom NSView:
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self A_singlePlane];
}
return self;
}
- (void)A_singlePlane{
CALayer *container = [CALayer layer];
container.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
[self.layer addSublayer:container];
CALayer *purpleLayer = [self addPlaneToLayer:container size:CGSizeMake(100, 100) position:CGPointMake(100, 100) color:[NSColor purpleColor]];
CATransform3D t = CATransform3DIdentity;
t = CATransform3DRotate(t, 45.0f * M_PI / 180.f, 0, 1, 0);
purpleLayer.transform = t;
}
- (CALayer *)addPlaneToLayer:(CALayer* )container size:(CGSize)size position:(CGPoint)point color:(NSColor *)color{
CALayer *plane = [CALayer layer];
plane.backgroundColor = [color CGColor];
plane.opacity = 0.6;
plane.frame = CGRectMake(point.x, point.y, size.width, size.height);
plane.borderColor = [[NSColor colorWithWhite:1.0 alpha:0.5] CGColor];
plane.borderWidth = 3.0;
plane.cornerRadius = 10.0;
[container addSublayer:plane];
return plane;
}
I have a view in interface builder with the class set as my custom NSView class. My custom view is set to have a layer. The result is a blank NSWindow. I do not receive any errors or warnings.
Does anyone see where my logical flaw is?
Related
I am using the ios default camera in my application. I would like to change something the edit view that shows after the user takes a photo.Normally, it shows a rectangle to crop, but I would like it to show a circle how would I do this.
Here is the solution which might help you to create crop overlay:-
- (void)navigationController:(UINavigationController *)navigationController didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if ([navigationController.viewControllers count] == 3)
{
CGFloat screenHeight = [[UIScreen mainScreen] bounds].size.height;
UIView *plCropOverlay = [[[viewController.view.subviews objectAtIndex:1]subviews] objectAtIndex:0];
plCropOverlay.hidden = YES;
int position = 0;
if (screenHeight == 568)
{
position = 124;
}
else
{
position = 80;
}
CAShapeLayer *circleLayer = [CAShapeLayer layer];
UIBezierPath *path2 = [UIBezierPath bezierPathWithOvalInRect:
CGRectMake(0.0f, position, 320.0f, 320.0f)];
[path2 setUsesEvenOddFillRule:YES];
[circleLayer setPath:[path2 CGPath]];
[circleLayer setFillColor:[[UIColor clearColor] CGColor]];
UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 320, screenHeight-72) cornerRadius:0];
[path appendPath:path2];
[path setUsesEvenOddFillRule:YES];
CAShapeLayer *fillLayer = [CAShapeLayer layer];
fillLayer.path = path.CGPath;
fillLayer.fillRule = kCAFillRuleEvenOdd;
fillLayer.fillColor = [UIColor blackColor].CGColor;
fillLayer.opacity = 0.8;
[viewController.view.layer addSublayer:fillLayer];
UILabel *moveLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 10, 320, 50)];
[moveLabel setText:#"Move and Scale"];
[moveLabel setTextAlignment:NSTextAlignmentCenter];
[moveLabel setTextColor:[UIColor whiteColor]];
[viewController.view addSubview:moveLabel];
}
}
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!
I have one view controller in which I have added UIScrollView & UIImageView programatically. I have added UIPichGestureRecognizer to the UIImageView. My UIImageView is added to UIScrollView as a subview.
My problem is when I try to pinch the image , it zoom in. But when I release the touches from screen it again come to its default size. I can not find the error in code. Please help me.
Below is my code
- (void)createUserInterface {
scrollViewForImage = [[UIScrollView alloc]initWithFrame:CGRectMake(20.0f, 60.0f, 280.0f, 200.0f)];
scrollViewForImage.userInteractionEnabled = YES;
scrollViewForImage.multipleTouchEnabled = YES;
scrollViewForImage.backgroundColor = [UIColor redColor];
scrollViewForImage.autoresizesSubviews = YES;
scrollViewForImage.maximumZoomScale = 1;
scrollViewForImage.minimumZoomScale = .50;
scrollViewForImage.clipsToBounds = YES;
scrollViewForImage.delegate = self;
scrollViewForImage.bouncesZoom = YES;
scrollViewForImage.contentMode = UIViewContentModeScaleToFill;
[self.contentView addSubview:scrollViewForImage];
imageView = [[UIImageView alloc]initWithFrame:CGRectMake(0.0f, 0.0f, 280.0f, 200.0f)];
[imageView setBackgroundColor:[UIColor clearColor]];
imageView.userInteractionEnabled = YES;
imageView.multipleTouchEnabled = YES;
UIPinchGestureRecognizer *pinchRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:#selector(pinch:)];
[pinchRecognizer setDelegate:self];
[imageView addGestureRecognizer:pinchRecognizer];
//[self.contentView addSubview:imageView];
[self.scrollViewForImage addSubview:imageView];
scrollViewForImage.contentSize = CGSizeMake(imageView.frame.size.width , imageView.frame.size.height);
}
-(UIView *) viewForZoomingInScrollView:(UIScrollView *)inScroll {
return imageView;
}
-(void)pinch:(id)sender {
[self.view bringSubviewToFront:[(UIPinchGestureRecognizer*)sender view]];
if([(UIPinchGestureRecognizer*)sender state] == UIGestureRecognizerStateEnded) {
lastScale = 1.0;
return;
}
CGFloat scale = 1.0 - (lastScale - [(UIPinchGestureRecognizer*)sender scale]);
CGAffineTransform currentTransform = [(UIPinchGestureRecognizer*)sender view].transform;
CGAffineTransform newTransform = CGAffineTransformScale(currentTransform, scale, scale);
[[(UIPinchGestureRecognizer*)sender view] setTransform:newTransform];
lastScale = [(UIPinchGestureRecognizer*)sender scale];
}
From what I can see the problem lies here:
scrollViewForImage.maximumZoomScale = 1;
You are setting the maximum zoom scale of the image to 1 x its full size. This means once you finish pinching the image, it will scale back to 1 x its size.
If you want to be able to zoom the image to a larger size, try settings this value to be higher than 1. e.g.
scrollViewForImage.maximumZoomScale = 3;
i'm trying to show an 'info' icon during a cursor 'rollover' on an NSTableView cell. i'm getting a copy of the cell's image, drawing the 'info' icon on it, and telling the cell to setImage with this copy. just drawing the icon will scale it and it won't be the same size in every one as the images in the table are different sizes. i'm not having a problem with the scaling or positioning the correct size icon.
my problem is that the replaced image is slightly blurry and it's edges are not crisp on close examination. the lack of edge makes it appear to be 'moving' slightly when the mouseEntered happens and the image is replaced.
i've tried a number of drawing techniques that doen't use lockFocus on an NSImage (drawing in CGBitmapContext, or using CIFilter compositing), and they produce the same results.
i'm using NSTableView's preparedCellAtColumn as it seems that drawing in willDisplayCell is unpredictable -- i read somewhere but can't remember where.
here is my preparedCellAtColumn method:
- (NSCell *)preparedCellAtColumn:(NSInteger)column row:(NSInteger)row
{
NSCell *cell = [super preparedCellAtColumn:column row:row];
if ((self.mouseOverRow == row) && column == 0) {
NSCell * imageCell = [super preparedCellAtColumn:0 row:row];
NSImage *sourceImage = [[imageCell image] copy];
NSRect cellRect = [self frameOfCellAtColumn:0 row:row];
NSSize cellSize = cellRect.size;
NSSize scaledSize = [sourceImage proportionalSizeForTargetSize:cellSize];
NSImage *outputImage = [[NSImage alloc] initWithSize:cellSize];
[outputImage setBackgroundColor:[NSColor clearColor]];
NSPoint drawPoint = NSZeroPoint;
drawPoint.x = (cellSize.width - scaledSize.width) * 0.5;
drawPoint.y = (cellSize.height - scaledSize.height) * 0.5;
NSRect drawRect = NSMakeRect(drawPoint.x, drawPoint.y, scaledSize.width, scaledSize.height);
NSPoint infoPoint = drawPoint;
infoPoint.x += NSWidth(drawRect) - self.infoSize.width;
[outputImage lockFocus];
[sourceImage drawInRect:drawRect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
[self.infoImage drawAtPoint:infoPoint fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
[outputImage unlockFocus];
[cell setImage:outputImage];
}
return cell;
}
[this is the enclosed scaling method from scott stevenson]
- (NSSize)proportionalSizeForTargetSize:(NSSize)targetSize
{
NSSize imageSize = [self size];
CGFloat width = imageSize.width;
CGFloat height = imageSize.height;
CGFloat targetWidth = targetSize.width;
CGFloat targetHeight = targetSize.height;
CGFloat scaleFactor = 0.0;
CGFloat scaledWidth = targetWidth;
CGFloat scaledHeight = targetHeight;
if ( NSEqualSizes( imageSize, targetSize ) == NO )
{
CGFloat widthFactor;
CGFloat heightFactor;
widthFactor = targetWidth / width;
heightFactor = targetHeight / height;
if ( widthFactor < heightFactor )
scaleFactor = widthFactor;
else
scaleFactor = heightFactor;
scaledWidth = width * scaleFactor;
scaledHeight = height * scaleFactor;
}
return NSMakeSize(scaledWidth,scaledHeight);
}
i need to support 10.6, so can't use new groovy lion methods.
thanks for your consideration...
Your code is setting the origin of the image to non-integral coordinates. That means that the edge of the image will not be pixel-aligned, producing a fuzzy result.
You just need to do this:
NSPoint drawPoint = NSZeroPoint;
drawPoint.x = round((cellSize.width - scaledSize.width) * 0.5);
drawPoint.y = round((cellSize.height - scaledSize.height) * 0.5);
That will ensure the image origin has no fractional component.
I'm writting a Cocoa app. I've wrote a code that can Drag&Drop one Image. But now I need to draw several Images by double click and D&D them. Each double click- new image, each click on existing image- starts D&D. Problem is in realization. I can't imagine a simple way of realization. Can anybody propose a solution?
Thanks.
#import "DotView.h"
#implementation DotView
- (id)initWithFrame:(NSRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
center.x = center.y = 100.0;
}
return self;
}
- (void)drawRect:(NSRect)rect {
NSRect bounds = [self bounds];
[[NSColor whiteColor] set];
NSRectFill(bounds);
[[NSGraphicsContext currentContext]
setImageInterpolation: NSImageInterpolationHigh];
NSSize viewSize = [self bounds].size;
NSSize imageSize = { 50, 40 };
NSPoint imageOrigin = center;
imageOrigin.x -= imageSize.width * 0.50;
imageOrigin.y -= imageSize.height * 0.50;
NSRect destRect;
destRect.origin = imageOrigin;
destRect.size = imageSize;
NSString * file = #"/Users/classuser/Desktop/ded.jpg";
NSImage * image = [[NSImage alloc] initWithContentsOfFile:file];
[image setFlipped:NO];
[image drawInRect: destRect
fromRect: NSZeroRect
operation: NSCompositeSourceOver
fraction: 1.0];
NSBezierPath * path = [NSBezierPath bezierPathWithRect:destRect];
}
-(void)mouseDown:(NSEvent*)event
{
NSPoint point = [event locationInWindow];
if(center.x<point.x+25 && center.x>point.x-25)
if(center.y<point.y+20 && center.y>point.y-20)
center = [self convertPoint:point fromView:nil];
}
- (void) mouseDragged:(NSEvent*)event {
[self mouseDown:event];
[self setNeedsDisplay:YES];
}
#end
Read:
Cocoa Drawing Guide
and
View Programming Guide for Cocoa
and
Drag and Drop Programming Topics for Cocoa
Once you've read these, ask more targeted questions - this is a bit too broad to answer simply.