Change the z-order of subviews on the iPhone - iphone

I'm developing a game. I'm using about 150 UIImageView to hold the graphics. I'm simulating a 3D enviroment, so i would like to change the z-order (how close is an object to the camera).
I know there exists :
[superWindow exchangeSubviewAtIndex:i withSubviewAtIndex:j];
But for some reason it's not working, some of the subviews disappear an re-appear.
Now I just remove all subviews and add it again in the correct z-order, this is ok with 50 subviews (on a 2G iphone) but with 120 it takes half a second so the gameplay sucks (I dont have and 3GS so i didn't try there).
I'm using so many subviews because each one is a square, then i colored it, resize it and move it somewhere in the screen. I'm holding the subviews under a NSMutableArray...

The iPhone documentation often warns about multiple UIViews nested, as it has a large performance hit after a certain point. If you start getting into issues one option is to render your UIViews into an image and using that to lower the number of on-screen views, but if you're simulating 3D that probably isn't going to help much since your composite view would need re-rendering too often.
The iPhone has full support for OpenGL ES, which allows for a real 3D environment. Take a look at some of the samples and/or a good book on the topic and you'll find that it's much easier to simply use OpenGL.

Z-order is an artifact of where your view appears in your superview's list of subviews. The last subview added to the superview is "on top".
So, to move a view to the be "on top", you remove it from its superview, then re-add it -- making it the last one and, therefore, on top.
Here, a view moves himself to the top of the z-order.
// move to the to in the z-order
UIView* superview = [self superview];
[self retain];
[self removeFromSuperview];
[superview addSubview:self];
[self release];
Note the [self retain] to prevent your dealloc if your superview is the only reference to you.

If you don't want to take the plunge to OpenGL ES, as Timothy suggests, you might want to look at replacing the UIViews with CALayers and placing them within a CATransformLayer. CATransformLayer is new in iPhone OS 3.0, and it lets you do a true 3-D layout of the CALayers. You can then set the zPosition property on your CALayers to locate them in the Z plane of the CATransformLayer. For more on 3-D layout of CALayers, I direct you to this article.
You can even add a nice perspective effect on the overall CATransformLayer by setting the m34 element in the CATransform3D applied to that layer.
Changing from UIViews to CALayers is pretty straightforward, because their structures have much in common.

Consider using a 2D game library like Cocos2D. I'm pretty sure that supports Z-ordering, and the performance will be vastly better than using UIViews.

I know this is old, but you can change the z order with bringSubViewToFront.
See this answer: How to set iPhone UI View z index?

Related

UIScrollView performance problem because of lots of labels

I've got a pretty big UIScrollView (contentSize 8000 x 960) with a lot of small labels.
The labels are only added if you scroll to the area where the label belongs to. So, at first, the scrooling is smooth, but as more and more labels are loaded, the performance suffers more and more.
What's the best solution to keep the scrolling smooth? Is CATiledLayer the way to go? Or should the labels off the view should be hidden or something like that?
Thanks a lot for your help!
Stefan
EDIT:
I got a huge performance boost when drawing some objects instead of using views; but now, I've got another problem; if I draw directly onto the UIScrollView, everything performs great. But if I lay a UIView on the UIScrollView and draw on that, performance goes down again (both times calling setNeedsDisplayInRect: in scrollViewDidScroll:).
So hierarchy:
UIWindow
UIView
UIScrollView <== drawing here
works fine.
But hierarchy:
UIWindow
UIView
UIScrollView (size 8000x960)
UIView (size 8000 x 960) <== drawing here
performs bad.
Any ideas why? I need the UIView above because the drawing should be ABOVE some UIViews; so I place the UIViews in the scrollView and draw in the view above...
The label reuse is one of possible solutions. Sometimes it doesn't help a lot. When a new UIView appears the drawRect method will be called and that may cause problems with animation.
Sometimes the best solution is to draw your labels (I mean text) directly using Core Graphics without creating UILabel object or something else. The CALayer will increase performance, but there is a possibility that it will not help you a lot.
But first of all you should remember that views with alpha = 0 or hidden = YES will not be drawn at all, so there is no penalty for using them. Maybe you should try to hide unused ones before using Core Graphics.
The best way would be to have just a few UILabels and reuse them. But you'll have to implement - (void)scrollViewDidScroll:(UIScrollView *)scrollView and do some reusable logic there. Depending on case it might be easier to use a UITableView and transform it 90 degrees, so it looks like a scrollview. That way you can the build-in reusable logic of the TableView.
For others seeing this post, I was able to drastically improve performance and keep UIViews in a scroller without using a table by enabling each view's "shouldRasterize" property. This property renders the view as an image while the view is in motion, causing it to not need to be reprocess for each pixel it moves. So, if I have a UIButton called button, it gets enabled like this:
button.layer.shouldRasterize = YES;
Did u try something similar to UITableViewCell
dequeueReusableCellWithIdentifier
Using a reuseIdentifer to reuse the once allocated labels..

How to create an timeline on iPhone

I am trying to create an inifite timeline in my iPhone app to scroll through time. I think I am going to use a UIScrollView to do that but I am not sure how to do that.
Am I supposed to create a reusable queue of views from scratch with views containing the days/months/years and reuse them when they go out of the screen ? (I have in mind the reusable cells from the tableviews).
Maybe there is a better way to do that ?
Thanks for your help !
As far as I know, UIScrollView doesn't have width limitation since 3.0. Nevertheless, you cannot use it to display large amount of data because it would take too much time to draw it and your application will work slow.
You can use UIView of width = 320.0 * 3 instead. Handle
- (void) touchesMoved: (NSSet*)_touches withEvent: (UIEvent*)_event
And apply
view.transform = CGAffineTransformMakeTranslation(-shift, 0.f);
Shift here can be calculated depending on delta X found from touches set. Affine translation allows to emulate smooth movement. When user releases their finger (touchesEnded), redraw your view (setNeedsDisplay) with shifted content and get it back:
self.transform = CGAffineTransformIdentity;
Don't do setNeedsDisplay while touchesMoved because it can affect performance if you are drawing graphs or calculating something.
For 2D map you would have to think about both X and Y and have 320*3 X 480*3 view :)
It's interesting task. Enjoy.
Well, the UIScrollView is finite, so you will hit the end at one point. You can of course move items around (back) to make sure you will never hit that limit.
You certainly want to do some caching/paging ala UITableView to make sure you only keep the minimal needed views in memory.
Ask a more specific question if you are ready for that :-)

Wrongly semi transparent views in iPhone objective C

I'm working on an iPhone game written in Objective C (which I'm new to). The problem is
that the views which are used to draw the sprites on screen are semi transparent. I have set
the alpha to 1.0 and the opacity to True. I have also used NSLog to confirm that the views' alphas are 1.0. I was using [self.view insertSubview:myView]; to add a view to be drawn but also tried [self.view insertSubview:myView aboveSubview:myOtherView]; just in case they were drawing onto each other.
I have tried searching google but can't seem to articulate a query which helps. I'm using OS 3.0. and I haven't included all the code because there is a lot of it. ANY help would be much appreciated.
Is the view to which you are referring a subview to another view that has an alpha set to a value less than 1.0? Alphas propagate down the the view hierarchy.
I'm not sure why you are getting semi-transparent views, but I would suggest not using UIViews for an iPhone game. Try a more game-oriented system like cocos2d. http://www.cocos2d-iphone.org/

UIView clipsToBounds property: Does it improve performance?

The documentation says that the clipsToBounds property of UIView will clip the drawing to the bounds, or more precisely that the subView can't draw outside of the bounds of the superView.
Sounds nice, but what does that mean in practice?
If I set that to YES, then my subView will automatically only draw those parts which are not outside the bounds of the superView. so it increases the overall performance or do I still have to make sure that I don't create any views that are not visible, i.e. inside a UIScrollView ?
I think it's the opposite: turning on clipping hurts performance because it has to set up a clipping mask. I vaguely remember reading this somewhere, but I can't find it now.
The use case for clipsToBounds is more for subviews which are partially outside the main view. For example, I have a (circular) subview on the edge of its parent (rectangular) UIView. If you set clipsToBounds to YES, only half the circle/subview will be shown. If set to NO, the whole circle will show up. Just encountered this so wanted to share.
The (possible) performance hit is only deterministic if you know the view hierarchy. As mentioned above, usually the renderer will use GPU cycles to draw the view UNLESS some view within the hierarchy uses drawRect:. This does not affect OpenGL ES application because drawRect:is omitted in this type of apps.
From my understanding, determining and displaying the clipped area may take less cycles than actually calculating/drawing/blending the whole view. As of OpenGL ES 2.0 clipping can be calculated in GPU.

uiview Transition problem

i have a UIview holding two other UIviews. that two subviews having 15 buttons and images. i have to translate the parent view. but the translation is not smooth in 3g phone. im using UIviewanimation and CGAffineTransformTranslate for translating the view. please help me for making it more smoother.
This is a though question to answer in a general way. I have had views that scrolled smoothly suddenly animating jerkily after just a small change. In short, you need to make sure to have as few subviews as possible and have as few non-opaque views as possible (pngs with alpha values translates to non-opaque UIImageViews).
If all else fails, you can render the whole view into an image, switch out the view for the image just before scrolling, and then re-insert the view again after the animation. That way, you are only moving one big and (hopefully) opaque view.
If you have many images make sure they are small-sized, otherwise theyd take up too much memory and there would be nothing to do. To my experience 4-5 large images(740-480) were too much for the phone to handle.