Core animation geometry for layer-backed view - macos

I have a layer-backed view, and want to understand how anchor point works for it and is it allowed at all to work with CALayer geometry properties (instead of using frame property of NSView)
First, quote from documentation:
The default value for anchorPoint is (0.5,0.5) which corresponds to
the center of the layer's bounds
But when I try to change value of anchor point to (0.5,0.5) directly, I got offset. Here is example, red area is the original position (when nothing applied to the anchor point), the button was moved to the bottom-left corner:
When I set anchor point to (0,0) button placed where it should be:
Update:
Here is the code I use to instantiate Button:
self.button = [[NSButton alloc] initWithFrame:NSMakeRect(130, 130, 100, 40)];
self.button.title = #"My Title";
self.button.wantsLayer = YES;
NSLog(#"Button anchor Point is : (%f;%f)", self.button.layer.anchorPoint.x, self.button.layer.anchorPoint.y);
[panelView addSubview:self.button];
What interesting, seems that for layer-backed view's the default anchor point is 0,0:
NSLog(#"Button anchor Point is : (%f;%f)", self.button.layer.anchorPoint.x, self.button.layer.anchorPoint.y);
produces (0.000000;0.000000)
After all, OS X Deployment target is 10.8

Here is quote from Apple documentation on NSView:
When using layer-backed views you should never interact directly with
the layer.
Seems this code cross the boundary of what you can do with layer-backed views.

Related

Xcode How do you make circular hitboxes on buttons?

I'm using Xcode 5 to make an UIButton. I made the button in storyboard and set the background image to a .png of a circle with transparency. I set up a simple action for the button to display how many times it was pressed in a label.
When I press the corners of the circle on the screen, it still adds to the score. So the button is still keeping its square hitbox, even though it has a round image as its background. I searched everywhere for a way to make a circular hitbox, but I can't find anything. Is this even possible? Is there an alternative way to do this?
The button responds to touch on corners because the bounding box of the button is a rectangle no matter what image you set for background.
To achieve a circular UIButton you must make a circular bounding box by simply using this code:
- (UIView *)setRoundedView:(UIView *)roundedView toDiameter:(float)newSize {
CGPoint saveCenter = roundedView.center;
CGRect newFrame = CGRectMake(roundedView.frame.origin.x, roundedView.frame.origin.y, newSize, newSize);
roundedView.frame = newFrame;
roundedView.layer.cornerRadius = newSize / 2.0;
roundedView.center = saveCenter;
roundedView.layer.masksToBounds = YES;
return roundedView;
}
In this method you can pass any UIView or subclass of UIView in your case UIButton. So in code you must create an IBOutlet of you button and in your -viewDidLoad method simply put this line of code:
self.btnMyButton = (UIButton *)[self setRoundedView:self.profilePic toDiameter:34];
Assuming you UIButton outlet is btnMyButton and set the diameter as per your requirement.
Hope this helps.
Don't forget to import QuartzCore Framework.

NSScrollView position is always bottom [duplicate]

I am developing Mac app. In this app, I am using a NSScrollView's instance as scrollView.
And I have set a customView which is an instance of NSView in this ScrollView as:
[scrollView setDocumentView:customView];
But, the NSScrollView's vertical Slider always points to the bottom of the view as:
I want that the slider always points to the top of the custom View as:
How can I make this change?
Plz help.
I have solved my problem by setting the scrollToPoint property of ScrollView's ContentView.
Here is the code:
[[scrollView verticalScroller] setFloatValue:0.0];
[[scrollView contentView] scrollToPoint:NSMakePoint(0.0, y)];
// here y = (difference b/w scrollView's content size height and scrollView's height)

draw CALayer into a CGContext

I have the following code:
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CALayer *sublayer = [CALayer layer];
sublayer.backgroundColor = [UIColor orangeColor].CGColor;
sublayer.cornerRadius = 20.0;
sublayer.frame = CGRectMake(20, 0, 300, 20);
[sublayer setNeedsDisplay];
[sublayer drawInContext:context];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
But when i view the return newImage, there is just an empty image. When i change drawInContext to renderInContext, then i got the above sublayer, but it seems like the coordinate system is mess up.
Any idea why drawInContext on the above did not work?
Try using renderInContext in place of drawInContext.
My understanding is that drawInContext is there to be overridden, whereas renderInContext is used to render the contents of a layer to the context.
From the documentation:
- drawInContext:
The default implementation of this method does not doing any drawing itself. If the layer’s delegate implements the drawLayer:inContext: method, that method is called to do the actual drawing.
Subclasses can override this method and use it to draw the layer’s content. When drawing, all coordinates should be specified in points in the logical coordinate space.
- renderInContext:
This method renders directly from the layer tree, ignoring any animations added to the render tree. Renders in the coordinate space of the layer.
The coordinate system isn't messed up, per se. Quartz uses a different coordinate system than UIKit. In Quartz, the Y-axis originates at the bottom-left of the framing rectangle. The values become larger as you travel farther "up" the rectangle. For a visual representation, see the documentation at
http://developer.apple.com/library/mac/#documentation/graphicsimaging/Conceptual/drawingwithquartz2d/dq_overview/dq_overview.html
This differs from UIKit in that UIKit's coordinate system origin is the top-left with y-axis values becoming more positive as you travel "down".
As for why drawInContext: doesn't work, you should also reference the docs for the CALayer class where it says, "Default implementation does nothing."
http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Reference/CALayer_class/Introduction/Introduction.html

In NSScrollView the vertical slider always points to bottom of the view

I am developing Mac app. In this app, I am using a NSScrollView's instance as scrollView.
And I have set a customView which is an instance of NSView in this ScrollView as:
[scrollView setDocumentView:customView];
But, the NSScrollView's vertical Slider always points to the bottom of the view as:
I want that the slider always points to the top of the custom View as:
How can I make this change?
Plz help.
I have solved my problem by setting the scrollToPoint property of ScrollView's ContentView.
Here is the code:
[[scrollView verticalScroller] setFloatValue:0.0];
[[scrollView contentView] scrollToPoint:NSMakePoint(0.0, y)];
// here y = (difference b/w scrollView's content size height and scrollView's height)

How do I get the inner/client size of a NSView subclass?

I am doing manual layouting for my Cocoa application and at some point I need to figure out what the inner size of a NSView subclass is. (E.g. What is the height available for my child view inside of a NSBox?)
One of the reasons is that I am using a coordinate system with origin at the top-left and need to perform coordinate transformations.
I could not figure out a way to get this size so far and would be glad if somebody can give me a hint.
Another very interesting property I would like to know is the minimum size of a view.
-bounds is the one you're looking for in most views. NSBox is a bit of a special case, however, since you want to look at the bounds of the box's content view, not the bounds of the box view itself (the box view includes the title, edges, etc.). Also, the bounds rect is always the real size of the box, while the frame rect can be modified relative to the bounds to apply transformations to the view's contents (such as squashing a 200x200 image into a 200x100 frame).
So, for most views you just use [parentView bounds], and for NSBox you'll use [[theBox contentView] bounds], and you'll use [[theBox contentView] addSubview: myView] rather than [parentView addSubview: myView] to add your content.
Unfortunately, there is no standard way to do this for all NSView subclasses. In your specific example, the position and size of a child view within an NSBox can be computed as follows:
NSRect availableRect = [someNSBox bounds];
NSSize boxMargins = [someBox contentViewMargins];
availableRect = NSInsetRect(availableRect, boxMargins.width, boxMargins.height);
If you find yourself using this often, you could create a category on NSBox as follows:
// MyNSBoxCategories.h
#interface NSBox (MyCategories)
- (NSRect)contentFrame;
#end
// MyNSBoxCategories.m
#implementation NSBox (MyCategories)
- (NSRect)contentFrame
{
NSRect frameRect = [self bounds];
NSSize margins = [self contentViewMargins];
return NSInsetRect(frameRect, margins.width, margins.height);
}
#end
And you would use it like so:
#import "MyNSBoxCategories.h"
//...
NSRect frameRect = [someNSBox contentFrame];
[myContentView setFrame:frameRect];
[someNSBox addSubview:myContentView];
The bounds property of NSView returns an NSRect with the origin (usually (0,0)) and the size of an NSView. See this Apple Developer documentation page.
I'm not sure (I never had to go too deep in that stuff), but isn't it [NSView bounds]?
http://www.cocoadev.com/index.pl?DifferenceBetweenFrameAndBounds

Resources