I have NSView container (with NSImageView and some other custom subviews). How to set its rotation properly? I tried to set angle through setFrameRotation: and set rotation matrix in views layer. But in these cases subview image becomes downscaled and clipped.
Update:
If I set rotation via [myView setFrameRotation: angle]:
almost fine, except text frame (drawing via [NSString drawAtPoint:...] and rotation anchor is at left-bottom corner (I want at bottom-center, [myView setFrameOrigin:...] does nothing)
If I set rotation via myView.layer.transform = CATransform3DMakeRotation (angle, 0, 0, 1):
frame bound remains unrotated and clips subviews (but this approach is more suitable for view container)
Related
on backed layer subclassed NSImageView method
- (void)setFrameRotation:(CGFloat)angle;
not working! So if its a backed layer, i should be using...
CATransform3DMakeRotation (CGFloat angle, CGFloat x, CGFloat y, CGFloat z)
ok, it is working fine but the view clips the layer. So when i make it a non-backed layer (means setWantsLayer=NO), setFrameRotation works. But this time i'm not able to rotate the image around the anchor point. It rotates around (0,0). So how am i able to rotate the view around the anchor point, not the layer?
Thanks.
I have a UIScrollView with a UIImageView inside it. The user can pan and zoom the image inside the scrollView.
I also have a UIImageView in the main view (above the scrollView), and the user can move that image around the screen.
I'm using CISourceOverCompositing to combine them both:
-(UIImage *) compositeFinalImage {
CIImage *foregroundImage = [CIImage imageWithCGImage:foregroundImageView.image.CGImage];
CIFilter *composite =[CIFilter filterWithName:#"CISourceOverCompositing"];
[composite setValue: foregroundImage forKey: #"inputImage"];
[composite setValue: [CIImage imageWithCGImage:backgroundImage.CGImage] forKey: #"inputBackgroundImage"];
CIContext *context = [CIContext contextWithOptions:nil];
CIImage *finalImage = [composite valueForKey:#"outputImage"];
return [UIImage imageWithCGImage:[context createCGImage:finalImage fromRect:finalImage.extent] scale:1.0 orientation:userImageOrientation];
}
...but the location and scale of the image has been lost when I make it a CIImage and the foreground image is always at the bottom left.
So I tried to use imageByApplyingTransform to move the position of the foreground image (and eventually I will have to apply scale transform as well), but I get the position from the ImageView, but the coordinates need to be in the native resolution of the background image itself... but the background image is moving around (which I guess means I have to take the ContentOffset into account somehow), and the background image has a certain scale, and the foreground image has a certain scale...
It seems weird that it's needed to re-produce all of the transformation with regards to different scale, rotation and position variables of each image...
This is the basic idea of what I'm trying to do (the left side is in the main view coordinates, while the right side is in native image coordinates).
Any help will be much appreciated!
Thanks!
I have a simple custom borderless NSWindow subclass which has a rounded rectangle shape.
In the content view of this window, I've added an NSScrollView.
How do I get the NSScrollView to clip its document view to the rounded rectangle shape of the NSWindow?
I've tried subclassing the NSScrollView, overriding drawRect: and adding a clipping path before calling super. I've also tried subclassing the document view and the clip view with the same technique but I cannot get it to clip.
BTW, this is on Lion with the elastic scrolling behaviour.
After much fiddling, I just discovered that NSScrollView's can be made to have rounded corners by simply giving it a backing layer and setting that layer's corner radius provided you also do the same to it's internal NSClipView. Both are required, which now makes sense, since it's the clip view that actually provides the viewable window into the NSScrollView's document view.
NSScrollView * scrollView = ...;
// Give the NSScrollView a backing layer and set it's corner radius.
[scrollView setWantsLayer:YES];
[scrollView.layer setCornerRadius:10.0f];
// Give the NSScrollView's internal clip view a backing layer and set it's corner radius.
[scrollView.contentView setWantsLayer:YES];
[scrollView.contentView.layer setCornerRadius:10.0f];
Even better IMO:
scrollView.wantsLayer = true
scrollView.layer?.masksToBounds = true
scrollView.contentView.wantsLayer = true
scrollView.contentView.layer?.masksToBounds = true
In Swift I have solved like this:
scrollView.wantsLayer = true
scrollView.contentView.wantsLayer = true
scrollView.layer?.cornerRadius = 20.0
scrollView.contentView.layer?.cornerRadius = 20.0
I am a newbie to Cocoa, I have a few doubts regarding NSImage.
Question1:
Changing the bounds origin of an image doesn't seem to have any effect. I expected the image to be drawn from the newly set origin but that doesn't seem to the case. Am I missing something ?
code:
NSImage* carImage = [NSImage imageNamed:#"car"];
[self.imageView setImage:carImage];
//Following line has no effect:
self.imageView.bounds = CGRectMake(self.imageView.bounds.origin.x + 100, self.imageView.bounds.origin.y, self.imageView.bounds.size.width,self.imageView.bounds.size.height);
Note: imageView is an IBOutlet
Question2:
I was trying to crop an image, but it doesn't seem to be cropping the image, I can see the complete image. What is that I am missing ?
code:
NSRect sourceRect = CGRectMake(150, 25, 100, 50);
NSRect destRect = CGRectMake(0, 0, 100, 50);
NSImage* carImage = [NSImage imageNamed:#"car"];
[carImage drawInRect:destRect fromRect:sourceRect operation:NSCompositeSourceOver fraction:1.0];
[self.imageView setImage:carImage];
Thanks
Changing the bounds origin of an image doesn't seem to have any effect. …
//Following line has no effect:
self.imageView.bounds = CGRectMake(self.imageView.bounds.origin.x + 100, self.imageView.bounds.origin.y, self.imageView.bounds.size.width,self.imageView.bounds.size.height);
That's an image view, not an image.
The effect of changing the bounds of a view depends on what the view does to draw. Effectively, this means you shouldn't change the bounds of a view that isn't an instance of a view class you created, since you can't predict exactly how an NSImageView will draw its image (presumably, since it's a control, it involves its cell, but more than that, I wouldn't rely on).
More generally, it's pretty rare to change a view's bounds origin. I don't remember having ever done it, and I can't think of a reason off the top of my head to do it. Changing its bounds size will scale, not crop.
I was trying to crop an image, but it doesn't seem to be cropping the image, I can see the complete image. What is that I am missing ?
[carImage drawInRect:destRect fromRect:sourceRect operation:NSCompositeSourceOver fraction:1.0];
[self.imageView setImage:carImage];
Telling an image to draw does not change anything about the image. It will not “crop the image” such that the image will thereafter be smaller or larger. You are telling it to draw, nothing more.
Consequently, the statement after that sets the image view's image to the whole image, exactly as if you hadn't told the image to draw, because telling it to draw made no difference.
What telling an image to draw does is exactly that: It tells the image to draw. There are only two correct places to do that:
In between lockFocus and unlockFocus messages to a view or image (or after setting the current NSGraphicsContext).
Within a view's drawRect: method.
Anywhere else, you should not tell any Cocoa object to draw.
One correct way to crop an image is to create a new image of the desired/adjusted size, lock focus on it, draw the desired portion of the original image into it, and unlock focus on the new image. You will then have both the original and a cropped version.
Another correct way would be to create your own custom image view that has two properties: One owning an image to draw, and the other holding a rectangle. When told to draw, this custom view would tell the image to draw the given rectangle into the view's bounds. You would then always hold the original image and simply draw only the desired section.
I am trying to make a NSScrollView with clipped corners, similar to the Twitter app:
I have a NSScrollView subclass which I added the following code:
- (void)drawRect:(NSRect)dirtyRect {
NSBezierPath *pcath = [NSBezierPath bezierPathWithRoundedRect:[self bounds] xRadius:kDefaultCornerRadius yRadius:kDefaultCornerRadius];
[path setClip];
[super drawRect:dirtyRect];
}
I expected the content of the NSScrollView to have rounded corners, but it is not respecting the clipped path. How can I do this?
UPDATE & CLARIFICATION
I know how to make a custom NSScroller, I know how to make it transparent overlay. All I am asking is how to make the NSSCrollView clip its corners, including everything it contains. The NSScrollView is inside a NSView which has a background that could change, meaning a view overlay to fake the rounded corners is not an option.
After much fiddling, I just discovered that NSScrollView's can be made to have rounded corners by simply giving it a backing layer and setting that layer's corner radius provided you also do the same to it's internal NSClipView. Both are required, which now makes sense, since it's the clip view that actually provides the viewable window into the NSScrollView's document view.
NSScrollView * scrollView = ...;
// Give the NSScrollView a backing layer and set it's corner radius.
[scrollView setWantsLayer:YES];
[scrollView.layer setCornerRadius:10.0f];
// Give the NSScrollView's internal clip view a backing layer and set it's corner radius.
[scrollView.contentView setWantsLayer:YES];
[scrollView.contentView.layer setCornerRadius:10.0f];
You can apply a mask to a view's layer:
[myScrollView setWantsLayer: YES];
[myScrollView layer].mask = ...;
The mask is another CALayer. So in this case you'd create a CALayer, set its background colour to opaque, set its bounds to match the scrollview, and give it a cornerRadius of, say, 8.0.
The result would be that the scroll view and all its contents would appear to be masked to a roundrect with a corner radius of 8px.
Have you tried overriding
- (BOOL)isOpaque {
return NO;
}
And setting the scroll view's -setDrawsBackground: to NO and just leave the view without clipping and just draw the corners with [NSColor clearColor] since this will also clear the underlying color and simulate a round effect.