NSImageView disappears when the parent NSView wants layer (setWantsLayer:YES) - macos

I have a simple custom NSView that has a label and an image. Currently the view works quite well (all the thumbs are instances of my custom view):
However, I want to set the opacity of these thumbnails. Setting viewInstance.layer.opacity doesn't work as the layer is nil. When I use [viewInstance setWantsLayer:YES] first somewhere, and I set the opacity, the opacity of the text changes (it is displayed correctly), but the image view disappears altogether:
I've tried creating a layer first, assigning it, and then calling setWantsLayer: after reading this question: How to add a CALayer to an NSView on Mac OS X but nothing changed:
CALayer *selfLayer = [[CALayer alloc] init];
[selfLayer setFrame:CGRectMake(0, 0, 100, 100)];
[self setLayer:selfLayer];
[self setWantsLayer:YES];
I've tried all combinations of creating a layer and displaying it for the image view too (just calling setWantsLayer:, creating layer and then assigning it, calling display method of it), but still nothing changes:
[self addSubview:self.imageView];
CALayer *imageLayer = [[CALayer alloc] init];
[imageLayer setFrame:CGRectMake(0, 0, 100, 100)];
[self.imageView setLayer:imageLayer];
[self.imageView setWantsLayer:YES];
I've tried adding the image view's layer as a sublayer of the main view and then displaying it:
[self.layer addSublayer:self.imageView.layer];
[self.imageView.layer display];
[self.layer display];
But still, the images won't display, whereas the text always displays correctly. When I comment out the code about assigning and wanting layers, images display again, but obviously, I can't use the layer opacity. I am on OS X Mavericks with OS X SDK 10.8. What am I doing wrong?
UPDATE: I ended up getting rid of NSImageView completely and drawing the NSImage directly into the layer by setting the layer's contents property. However, this is just another approach which solved my problem for this project, it still doesn't answer the original question.

I ended up getting rid of NSImageView completely and drawing the NSImage directly into the layer by setting the layer's contents property. However, this is just another approach which solved my problem for this project, it still doesn't answer the original question.

Related

Can NSView's CALayer can be a sublayer of Other View?

It seems following codes does not work.
WebView *wView = [[WebView alloc] init];
[[wView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.google.com"]] ];
[wView setWantsLayer:YES];
NSView *v = [[NSView alloc] init];
v.frame = CGRectMake(0, 0, 100, 100);
[v setLayer:wView.layer];
[v setWantsLayer:YES];
What I want to is use other view's layer, for example NSTextField's layer or Webview's layer, as sublayer of other view
can this work?
In your example the WebView is layer-backed and the NSView is layer-hosted. This means that from the perspective of the web view it owns the layer and doesn't expect any thing to interact directly with it. From the perspective of the view, the same layer can be manipulated directly.
Apple's documentation on this is quite clear,
Layer-backed
When using layer-backed views you should never interact directly with the layer. Instead you must use the standard view programming practices.
Layer-hosted
When using a layer-hosting view you should not rely on the view for drawing, nor should you add subviews to the layer-hosting view.
By having this hybrid scheme you are probably setting yourself up for trouble because it conflicts with guidelines! I would try another way of solving your problem.

Autolayout NSImageView in NSView - scale size. Programmatically set NSLayoutConstraint

I have an NSImageView in a NSView set up in IB. The NSImageView is exactly the same size as the NSView.
Everything works fine and the NSImageView have the same size as the NSView when resizing the window.
BUT, now I've added an animation (move from A to B) to the NSImageView and that will mess up the constraints that's been set up in IB. So I have to do this programmatically.
How could I programmatically set NSLayoutConstraint to have my NSImageView have the same size as my NSImageView (the superview)?
UPDATE:
Just to give you guys some more information. My app uses a split view (three views) and instead of adding the NSImageView in IB I now add it programmatically. I add my new view (which shall be scalable to it's parent view) to the third view in the split view.
Do you think the split view is causing these issues?
UPDATE 2:
Ok, I'm closer to fixing this. I removed the NSImageView from the view, and added a NSView instead. The NSView scaled fine, but as soon as I added the NSImageView it stopped working in the way that the NSImageView won't scale after resizing the window.
In other words, the problem lies in the NSImageView itself. It won't scale after resizing the window...
SOLVED
I solved it by using PDF View instead of image view (it was a PDF I wanted to show). I set the autoScales property to YES on the PDF View.
I assume you already have references to the views in the example below:
NSView * parentView;
NSImageView * imageView;
[imageView setTranslatesAutoresizingMaskIntoConstraints:NO]; //Required to opt-in to autolayout
[parentView addSubview:imageView]; //Subview must exist before adding constraint.
NSDictionary * views = NSDictionaryOfVariableBindings(imageView);
[parentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[imageView]|"
options:0
metrics:nil
views:views]];
[parentView addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[imageView]|"
options:0
metrics:nil
views:views]];

NSImageView fails to setImage?

I'm trying to create a simple ImageView that just loads an image from disk, but this isn't working (I put it in my applicationDidFinishLoading):
NSString *file = [#"~/update.png" stringByStandardizingPath];
NSImage *image = [[NSImage alloc] initWithContentsOfFile:file];
[wView setImage:image];
Apparently the image for the NSImageView isn't being set, because if I NSLog [wView image], I get (null). I'm pretty sure I'm making a beginner mistake here, but what?
The file and image load fine; if I draw the image to an NSView it shows up fine. wView isn't nil, and I tried making another project with the default window's view a custom NSImageView subclass whose initWithFrame: calls setImage. Still nothing.
(OP here with an actual account)
So it turns out that setImage doesn't work on an NSImageView that's explicitly constructed in IB, if you get what I mean. I made an NSView subclass that constructs an NSImageView inside it and calls setImage, and that worked fine. Really annoying.
Most likely, wView is nil. The most common reason for this is when a class that's instantiated in the nib with a connection to a view also gets instantiated a second time in code.

Gray border when using NSBorderlessWindowMask

Whenever I try to create a custom window using NSBorderlessWindowMask and set an NSView (for example an NSImageView) as its contentView, I get a 1px gray border around the NSView and I don't seem to be able to get rid of it.
I have followed several approaches including Apple's RoundTransparentWindow sample code as well as several suggestions on StackOverflow.
I suspect the gray border is either coming from the window itself or the NSView.
Have any of you experienced this problem or do you have a possible solution?
The code is fairly straightforward. This is the init method of the custom window:
- (id)initWithContentRect:(NSRect)contentRect styleMask:(NSUInteger)aStyle backing:(NSBackingStoreType)bufferingType defer:(BOOL)flag {
self = [super initWithContentRect:contentRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];
if (self != nil) {
[self setAlphaValue:1.0];
[self setBackgroundColor:[NSColor clearColor]];
[self setOpaque:NO];
}
return self;
}
To test this, in IB I place an NSImageView in that custom window WITHOUT border and yet the image in the NSImageView has a border. The same goes for other NSView subclasses, such as NSTextField, NSTableView.
In addition, I also noticed that the same is happening with the sample application (RoundTransparentWindow) of Apple. Is it even possible to draw an NSView in a custom window without a 1px border?
Thanks
Are you sure this happens when you use a regular NSView with no drawing? I bet not. Other controls (like NSImageView)have borders. Maybe you should double check to make sure they're turned off whe possible.
Update - How do you get your view into your window? You don't include that code. I created a basic test project (download it here) with an image well and it works just fine. See for yourself.

NSTextView not refreshed properly on scrolling

I have a NSTextView with a sizeable quantity of text. Whenever I scroll however, the view isn't updated properly. There are some artifacts that remain at the top or the bottom of the view. It appears that the view doesn't refresh itself often enough. If I scroll very slowly the view updates correctly though. If I add a border to the view everything works perfectly, borderless view is the one that has a problem. Here's a link to a screenshot:
Thanks
Have you set the setDrawsBackground and copiesOnScroll propertes for either the NSScrollView or the NSClipView?
The first thing I would suggest is turning off the "draws background" property of the NSScrollView:
[myScrollView setDrawsBackground:NO];
Note that this should be set on the NSScrollView, and not on the embedded NSClipView.
The following excerpt from the documentation may be relevant:
If your NSScrollView encloses an NSClipView sending a setDrawsBackground: message with a parameter of NO to the NSScrollView has the added effect of sending the NSClipView a setCopiesOnScroll: message with a parameter of NO. The side effect of sending the setDrawsBackground: message directly to the NSClipView instead would be the appearance of “trails” (vestiges of previous drawing) in the document view as it is scrolled.
Looks like the text field isn't even in the scrolling-area... Are you sure something isnt overlapping it?
I had a similar trouble - artifacts develop when the NSTextView is embedded in another scrollview (ie. a NSTableView).
I actually turned on the setdrawsbackground, and then added a nice color to make it disappear again.
-(void)awakeFromNib{
NSScrollView *scroll = [self enclosingScrollView];
[scroll setBorderType:NSNoBorder];
[scroll setDrawsBackground:YES];
[scroll setBackgroundColor:[NSColor windowBackgroundColor]];
}
This in combination with a scrollWheel event let me use the NSTextView in a NSTableView.
-(void)scrollWheel:(NSEvent *)theEvent{
NSScrollView *scroll = [self enclosingScrollView];
[[scroll superview] scrollWheel:theEvent];
}
I had the same trouble some time ago. I don't remember how I solved it.
Try to place the NSTextView to another view if the superview is a custom view. Just to see what will happen.

Resources