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

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.

Related

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

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.

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]];

Cocoa: [self.view setWantsLayer:YES] brings that view above other subviews?

Simply, I have an NSView with a bunch of subviews. In the awakeFromNib method (inside the view's controller), I decided to add the following:
[_backgroundImageView setWantsLayer:YES];
[[_backgroundImageView layer] setShadowOpacity:1.0f];
[[_backgroundImageView layer] setShadowOffset:NSMakeSize(-3, -3)];
The backgroundImageView is at the back of all the subviews. But, when I added the previous code, it draws the shadow correctly, but also draws the backgroundImageView above all other layers. Why? How I can Fix that?
You need setWantsLayer:YES in code for the superview.
Turn's out I should enable the layer for the superview (self.view), too. Not only that, but I should tighten up the imageView's frame, or else it will be scaled "axis independently" even though it is set to "Proportional up or down".

Xcode: UINavigationController in a subview

I'm new in Xcode (and also here, in stack overflow) and I'm trying to build an application which contains a small UINavigationController (with a TableView inside) on the top of the window. So it should not be in full screen, it's just a little part of the GUI (just like a textField, or any other kind of component).
I've read that UINavigationController is designed to be displayed on the entire screen, but would it be possible to do it anyway?
If I can't, I'll probably have to write my own UINavigationController-like and TableViewController-like, with all transition effect (between 2 TableView) etcetera...
Thanks in advance for your help!
I founded the solution in a book and it's quite simple. I have to create the UINavigationViewController programmatically:
tableViewController = [[MyTableViewController alloc] initWithNibName:#"MyTableViewController" bundle:nil];
navCtrl = [[NavigViewController alloc] initWithRootViewController:tableViewController];
[navCtrl.view setFrame:CGRectMake(40, 40, 150, 200)];
[window addSubview:navCtrl.view];
[self.window makeKeyAndVisible];

How do you put a normal control into an NSView?

What I'm actually trying to do is put a WebKitView into a ScreenSaver (which inherits NSView). I'm totally new to MacOS X and Cocoa (but I'm very familiar with Objective-C and used some parts of GNUStep). Do I need some laying out? I want to show only one control in the whole NSView.
In your initWithFrame:isPreview: method, create a WebView in the usual way, then, send yourself an addSubview: message, passing the web view:
webView = [[WebView alloc] initWithFrame:frame];
[self addSubview:webView];
If you're wondering what rectangle you should pass as the WebView's frame, read the View Programming Guide. Also, don't forget to release the webView in dealloc (or autorelease it in initWithFrame:isPreview:).
Once you have your web view, you'll need to load a page into it. Set a suitably long animation interval (at least a couple of seconds), and load the page in animateOneFrame:
- (void) animateOneFrame {
[[webView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://google.com/"]]];
}
You may also want to handle WebViewProgressFinishedNotification, and put off re-loading the web view until that happens (to compensate for slow or soaked connections). You'll do this with an instance variable, which you set to YES in both initWithFrame:isPreview: and your notification-handler method, and test and set to NO in animateOneFrame:
- (void) animateOneFrame {
if (hasFinished) {
[[webView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://google.com/"]]];
hasFinished = NO;
}
}
[aScreenSaverView addSubview:aWebKitView];
But why add a UIWebView into a screen saver view when you can just make the UIWebView take up the full screen on its own? Introducing view hierarchies where they are not needed is not a good idea because it increases the processing needed to display the interface.
You can also not worry too much about your animation interval by calling
[self stopAnimation];
at the end of your animateOneFrame method.

Resources