How would I change from one view to another with a slide transition?
Thanks.
Place them side by side, and use NSViewAnimation to perform the animation.
This may turn out tricky if the views' size can change. Doubly so if the two views are not the same size as each other.
Marcus Zarra gives a good example of how to use Core Animation to achieve this effect in his post on how to implement a wizard. It's very simple to do using subviews and a CATransition.
Implement all the actual drawing using CALayers. (Having not used Core Animation myself, I can't get more specific.) Put them in a single view, hosting that layer hierarchy, and use Core Animation to perform the slide transition.
This may not work so well if the views are not display-only—that is, if they host controls that the user can interact with. Layers are more or less display-only, since you can't put a view in a layer, and only views, not layers, are responders.
Related
I've been working hard, searching the internet on that problem for 3 days and I'm now running out of ressource.
Currently porting an iOS app to MacOS (deployment 10.11). The problem:
I have a view hierarchy as below:
NSScrollview
documentView
grouping view
tiling view one
array of NSImageView (each one being a tile)
tiling view two
array of NSImageView (each one being a tile)
The two tiling views are overlaying completely, depending of UI one may be hidden or the second one has opacity set below 1.0 to blend the two tiled view.
Because of opacity requirement, as well as performance, views are CAlayer backed. This is done from IB where the to NSScrollview is checked for Core Animation. Thereoff, all the view tree is (implicitly) layer backed.
Works as expected, scroll, magnify, etc..
Then I need to make an image out of the document view to generate an SCNMaterial content (3D view).
On iOS the documentView renderInContext works as expected, and allows an image to be created.
On Appkit the context stay transparent, so is the image, a valid object while as if clearColor.
If the documentView.canDrawSubviewsIntoLayer is set at creation, the view tree renders OK. This can't be the solution since it prevents opacity setting to work.
Even when one tiling view is hidden (no opacity compositing) rendering fails.
I read that some kinds of views are not rendered. I don't use them. There are no filters, no masks, beside a default masksToBounds setting on all the view tree. I don't know why and where it is set. I tried to unset it on all the views at creation with no success. It is set again somehow, on the grouping view below the documentView. This may be the problem but why this property is out of my control ?
Alternative way to get view tree rendering, bitmapImageRepForCachingDisplayInRect: / cacheDisplayInRect:toBitmapImageRep: works the same : ok with canDrawSubviewsIntoLayer, KO otherwise. Apple code examples to make a texture out of a view are using either one of the two methods.
There are plenty of posts, mainly on SO, complaining about CALayer renderInContext and code to custom render a layer tree. Nevertheless, most are quite old and now there must be a simple standard way to achieve it.
Edit: among other attempts, I tried to set each view wantsLayer, with no success.
Well, as often when you post a request for help, you finally find the answer by yourself… Here it is:
Given the view tree as listed in the question, I achieved to render it by setting canDrawSubviewsIntoLayer on each tiling view. This way, the opacity compositing between layers is working, AND the views are rendered.
I post this as an answer, because it solves the problem.
As of WHY this works, here is my guess, but this is not a authorised answer: Each NSImageView tile, subviews of tiling view, have their origin set to their frame. This is not a transform on the layer but a position of the frame in the coordinates of the tiling view. This is a difference with the iOS code version where the tiles are positioned by a transform. I'm going to test further, and see if using a transform rather that a frame origin makes a difference to renderInContext.
Edit: after more testing it appears that the iOS version has a transform AND an offset to the tile.
So the only clue is that the layer system get lost when rendering in context on OSX when some subview have an offset ??
Summary:
The key point to the solution is to find the right layer where to set canDrawSubviewsIntoLayer
I'm scrolling in a huge set of data points (CGPoints in a custom view, like a graph) and its obviously slow and laggy. Is there a common way to load and draw only the chunk of data I need to display? Does [[[myScrollview] documentView] documentVisibleRect] the trick?
I also want to zoom in and out and therefore change the data point's detail.
Thanks for any tips.
How you do this is completely up to you. It's your custom view, you can draw whatever you like. Your view controller should keep track of the zoom level and current location and your view should just draw that part of the data.
There's nothing magic that's going to make this easier, you have to program it yourself.
I'm wondering how to implement views similar to the conversation views in mail (for Lion).
http://images.apple.com/macosx/whats-new/images/mail_conversation_screen.jpg
I want the effect where it looks like a sheet of paper laying on the background.
I'm thinking that it may just be a view based table view.
A nudge in the right direction would be fine. Just need to know where to look to find out how to do it.
Thanks in advance.
It could be a view based table view or just a normal container view with some simple tiling logic (ie, "roll through each subview and set their frames"). The effect you're looking for, though, can be easily accomplished with layer-backed views with a background shadow enabled.
There are several perfectly valid approaches to this goal (the layout and drawing parts). Pick one, start down the path, then post questions as problems arise.
Is there any Cocoa control that is capable of drawing tile maps with multiple layers and multiple texture sources which can also intercept touches into single tiles? Having multiple layer support is not a real requirement but an optional feature (the views could still be stacked). Hardware acceleration is not needed at all.
So far I have toyed around with NSMatrix, IKImageBrowser and NSCollectionView but non of them felt like a good solution for the problem. Ideally I need an control similar to the one in Tiled.app. Is there anything, third party or built-in, or do I have to handcraft this control?
I fear that you will be hardly able to find a ready-to-use control for managing tile maps.
If I had to implement something like that on my own, I would consider using CATiledLayer, since this is the closest thing to a tile map control that I know of.
From CATiledLayer Reference:
CATiledLayer is a subclass of CALayer providing a way to asynchronously provide tiles of the layer's content, potentially cached at multiple levels of detail.
There is a nice sample by Bill Dudney (the author of "Core Animation for MacOS and the iPhone"). This sample could provide you a solid foundation for your own project, though it only displays one single PDF, allowing you to zoom in the area you clicked on (this requires rereading the tile at a different detail level).
Another interesting introduction can be found here. This is more step-by-step, so you might start with this.
Finally, on Cocoa is my Girlfriend there is a nice article, although it focuses on iOS, but you may find it anyway relevant.
Cocos2D supports building mac applications now
Article on cocos2d stating this: http://www.cocos2d-iphone.org/archives/1444
Aee here for how to do it: http://chris-fletcher.com/tag/cocos2d-os-x/
Aee here on how to use TMX tile maps with Cocos2D to build tile based maps: http://www.cocos2d-iphone.org/wiki/doku.php/prog_guide:tiled_maps
This means you can use the power of Cocos2d and you will have to write much less code to get to where you want with a tile based map.
If you don't want to use Cocos2D:
It seems you would have to code it yourself, but it shouldn't be too hard to do.
First you can create your .TMX file using the tile editor "Tiled.app" then you would need to parse the XML using a standard xml library for Cocoa.
To lay out the tiles use a UIView for the overall container and then create a tile class that holds your tile display information and responds to clicks the tile class should extend UIView. For the tile class allow the assigning of a click delegate and assign your ViewController as the click delegate for all tiles so you can handle clicks easily with the clicked tile being passed to you.
Loop through your xml data and create and position the tiles in the overall UIView by using the tiles width/height and your tilemaps rows/columns.
I think in about a day or 2 you could have the tile map being rendered and clickable using the standard TMX format which will allow you to edit your map in "Tiled.app"
The TMX standard is covered here: https://github.com/bjorn/tiled/wiki/TMX-Map-Format
route-me might fit the bill.
I have an NSView subclass that can be dragged around in its superview. I move the views by calling NSView's setFrameOrigin and setFrameRotation methods in my mouseDragged event handler. The views are both moved and rotated with each call.
I have multiple instances of these views contained by a single superview. The problem I'm having is that, as one view is dragged over another, it leaves artifacts behind on the view it's eclipsing. I recorded a short video of this in action. Unfortunately, due to the video compression the artifacts aren't very visible.
I strongly suspect that this is related to the simultaneous translation and rotation. Quartz Debug reveals that a rectangle of the occluding (or occluded) view is updated as another view is dragged across it (video here); somehow this rectangle is getting miscalculated by the drawing engine, so part of the view that should be redrawn isn't.
The kicker is I have no idea how to fix this. I can't find any way to manually specify the update rect in the docs, nor am I sure that's what needs to happen. Any ideas? Thanks!
You might also consider using CALayers instead of views. Unlike views, layers are intended to be stacked with their siblings.
For a possible least-effort solution, try making the views layer-backed; it may or may not solve this problem, but it's worth a try.
Views aren't really designed to be stacked in an interactive fashion. Can be done, but edge cases abound.
Generally, for this kind of thing you would use a Cell like infrastructure if you want to do in-view dragging (See the Sketch example) and you would use the drag-n-drop infrastructure if you want to drag between views or windows (or apps).
If you really want to drag a transformed view over the top, you'll need to invalidate a rectangle of the view underneath the view being dragged. The rectangle will need to be bigger by a few pixels than the total area (unrotated/untransformed) that is obscured by the view being dragged. The artifacts are, effectively, caused by rounding error; diagonal lines are just an estimate on a raster drawing system.
See the method:
- (void)setNeedsDisplayInRect:(NSRect)invalidRect;