How to set order of display in Objective-C - iphone

I'm trying to mix between UIImageView drawing and line drawing using CGContext path draw commands, but the draw order is not correct.
I need to draw the path on top of the images but get the reverse.
The way I implemented it:
Setting UIImage within a UIImageView and adding the UIImageView as a subview of the main view.
Next I use the 'drawRect' (refresh draw function) to draw the path using the UIKit CGContextStrokePath function.
Now, other than using the Context image draw function directly (I want to avoid that because I reuse my image resources by several UIImageViews), is there a way to set the order correctly (a flag set maybe)?
The problem again is that lines/path are drawn before the UIImageViews (which are drawn automatically via the connection to the parent UIView), hence they are not visible over the images / UIImageViews.
Thanks

You can try implementing this through Quartz Core using layers (see the CALayer class documentation). Basically, you can have layers hierarchies. You associate each UIView to a different layer, then the layers are rendered together providing a single, composite layer. Besides, you can also apply transforms and animations to layers.
You need to import the QuartzCore header and do something like
#import <QuartzCore/QuartzCore.h>
UIView *mainView = [[UIView alloc] initWithFrame...
UIImageView *imageView = ...
CaLayer *mainViewLayer = mainView.layer;
[mainViewLayer addSubLayer: imageView.layer];
Then, when mainView appears on the screen, all the sublayers are merged together and rendered on screen. What happens is that each view renders its layer, while mainViewLayer is rendered merging together the two layers.
Let me know if this works for you.
You can have as many layers as you like. You can create an arbitrary hierarchi by using the CALayer methods
– addSublayer:
– removeFromSuperlayer
– insertSublayer:atIndex:
– insertSublayer:below:
– insertSublayer:above:
– replaceSublayer:with:

The contents of the topmost (in this case, last added) subview will appear in front of all other views. If you add an image subview and draw into its parent view, the image will appear in front of any drawing you do in that parent view.
You should draw into a new view you add to the main view only after adding the UIImageView.
You could also use bringSubviewToFront: and sendSubviewToBack: to manually reorder views if you need to.
(From your post, it's unclear which view you're drawing into, but I assume you're drawing into that main parent view which would explain this behavior.)

Related

iPhone: In a custom view, how to draw something on top of everything else in the view?

So I made a UIView subclass let's called it 'MyView' that simply draws a line inside the DrawRect method.
I then drag a UIImageView in interface builder and put it inside MyView. But now when I run the program it's obscuring the line that I'm drawing. I'm wondering, is there a way for me to draw the line on top of the image that I have dragged into my View?
No, you'll have to reorganise the view hierarchy. CoreGraphics uses a painters model so views behind will always be drawn over by views infront. To solve this you could use a container view that holds your image view and has a transparent view (line drawing view) that sits over the image view.
Another option is to draw the image using core graphics calls in your drawRect method and then draw the line over it.
One way is to have whatever adds MyView to add your UIImageView on top of MyView. It's not ideal (you probably have good reasons for keeping MyView and the UIImageView in a single class) but definitely solves your problem (I recently did this, only, I added it to the keyWindow =)
I would use a CAShapeLayer that has a path representing the line, and insert that layer ahead of the built-in view layer. Then it should draw on top.

CALayer and UIView display order

I have a CATiledLayer within a UIView and the UIView also contains a subview.
How can I make sure that the subview is always drawn above the layer?
Most of the time I get the tile layer covering the subview.
By default all layers (hence views) added in the last are drawn on the top. You can change the default with -insertSublayer:below: and similar methods:
[view.layer insertSublayer:tiledLayer below:thatSubview.layer]

Can I use DrawRect on a UIImageView loaded from a NIB?

I've created a NIB file with some button controls on it, and as a background it has an ImageView which contains a PNG file loaded from my project.
What I want to do is to draw on top of the ImageView - imagine that my UI is a clockface and I want to draw the hands of the clock on top of the background image.
Is it the correct approach to try to subclass the UIImageView and use its DrawRect as when I use the DrawRect of the default view I don't see anything on the screen?
I'm a little lost as I'm finding this particular bit of the documentation hard to follow.
Thanks.
Create a new custom UIView (e.g. named HandsView) that sits on top of your background view (by adding it as a subview of the UIImageView). In the custom view, you can use the drawRect method. Make sure, you clear the context to transparent, so that the background image can be seen below the HandsView.
If you just want to draw turning hands, you can also try to use two fixed UIImageViews with the images of the hands and use the transform property to apply a rotation.

How to add a naked CALayer as "subview" to a UIView?

I think that adding a CALayer as "subview", somehow, does save a lot of memory. A UIView always comes with 3 copies of it's content bitmap (presentation layer, render tree and another one, plus the view itself, so every pixel is saved 4 times). But how could that be done?
UIView is basically a wrapper for CALayer. So you can add a layer directly to the view's layer. This can be done by calling
[[theView layer] addSublayer:newLayer];

Subclassing UIView or composing with UIView

I'll start by saying what I want to do because I'm unsure if I'm asking the right question. I'm making a grid based map and am going to hold an array of objects to keep the state and presentation of the map. Each object will be of a Tile class. Should I be subclassing UIView or sublass NSObject and have an ivar of UIView. I was also planning to have a UIImageView inside the UIView to load the image that represents that bit of the map. Lastly, I wanted to load the view from a NIB.
Individually I know how to do each of these things but unsure of the best practice. Any thoughts?
Have you considered Core Animation layers? You can create a single view with a grid of layers each with their own bounds and position within the view. It sounds like it might give you what you need. On the phone, setting a layer's contents with an image is as simple as this:
CALayer *gridLayer = [CALayer layer];
[gridLayer setContents:(id)[gridImage CGImage]];
[gridLayer setBounds:[gridImage bounds]];
// Position the layer's center a x:25.0 y:25.0 within the view
[gridLayer setPosition:CGPointMake(25.0f, 25.0f)];
[[view layer] addSublayer:gridLayer];
The variable gridImage is a UIImage* you've allocated somewhere. You would just need to calculate your layer rects and positions and place them accordingly.
Make sure you have a clear definition of which particular classes/objects comprise your model, your controller and your view. Your data and data logic should be in the model, your display in the view and you should tie them together with the controller.
The simplest way to accomplish a grid is to use UIImageViews that are positioned by a single controller. The model will track the logical relationships between the map squares and relay that to the controller which will load the images into the UIIMageView. The controller will handle loading everything from nib.
However, using CALayers is the preferred cutting edge method. The basic model,controller, view relationship is the same except that the CALayers replace the ImageViews.
If I uderstand right, you can make subclass of UIImageView.