UIScrollView lags when adding UIView with multiple views - iphone

I've been working on a Crosswords app for a while and this problem keep returning no mater what i try.
The actual game runs in an UIScrollView because the player should be able to zoom, pan etc.
To the UIScrollview i have added a UIView. First i tried to add multiple UIImageViews and UILabels to the UIView but it resulted in very bad scrolling performance.
Now I've tried to create 3 subclassed UIViews where i wrote a custom drawRect method for each of them. I need 3 UIVIews because only two of the them needs to be redrawn, but not at the same time. The third one contains the clue numbers which are constant.
My UIScrollView hierarchy look like this:
UIScrollView
UIView
UIImageView (show the game board image)
UIView (shows the marked row/column)
UIView (shows the text the user writes)
UIView (shows the clue numbers)
I think the problem is that i have the UIImageView + 3 UIViews in one UIView. When I try to make this hierarchy it doesn't lag, but I'm not able to zoom, pan, scroll etc.:
UIScrollView
UIImageView (show the game board image)
UIView (shows the marked row/column)
UIView (shows the text the user writes)
UIView (shows the clue numbers)
Can you please try do guide me in the right direction. I will appreciate if I do not have to change too much, because the code in the three UIVIews are pretty long.
Thanks in advance :)
EDIT
Screenshot: http://crosswords-plus.com/puzzles/screen.png

First off, I'd recommend shrinking your UIScrollView and pulling the UIView containing the clues out of it. It sounds like it doesn't need to pan/zoom, so you're just adding to the overhead by having it contained inside the UIScrollView.
Secondly, it's hard to give much of an answer without seeing your implementation, but it seems to me that it's possible to turn the UIImageView/UIView/UIView hierarchy into 1 subclass that draws empty, blacked out or filled-in squares plus row/column numbering as necessary. That way, you only have 1 UIView in the UIScrollView and all of this is probably much simpler.
Is that helpful? Is there a reason you're using a UIImageView for the background? Is there a reason you're separating the row/column numbering from the text the user has entered?

Related

UIScrollView lags on iPhone

I'm trying to create a crossword app. The game runs in a UIScrollView, because the player should be able to zoom, scroll etc. The largest crossword are 21x21 which means there need to be 441 touchable tiles. What i've tried so far were to create an UIView and added it as a subView to the UIScrollView. Then I call a method that creates 441 custom UIButtons and set the backgroundImage.
Some of the UIButtons need to have a custom label overlay, so i added a UILabel and set it on top of the UIButton.
When I run the app in simulator all works as it should, but when i test it on an iPhone 4 the UIScrollView lags a lot.
I don't know if this the way to do it? Can you maybe try to guide me in the right direction of how to do this so the UIScrollView won't lag on a device.
Thanks in advance.
Big UIScrollViews are difficult to make smooth without some sort of caching mechanism, such as the one provided by UITableView.
One thing you can do, however, to make life easier for your rendering, is to make sure to use opaque backgrounds whenever possible. In stead of making a view transparent you should make it the same color as its underlying view. This is something that does help.
Also, I have experienced better performance using imageWithContentsOfFile: in stead of imageNamed: for initializing images to be used in a UIScrollView.
In order to not keep all those buttons in memory, you should work with reusable table view cells, this will really improve the scroll performance. Here's one component that could make your life easier: DTGridView, there are also others (you can check Cocoa Controls)

Adding views on top of UIScrollView

When you add a subView to UIScrollView, should this change the smoothness, or anything else for the UIScrollView? For example, if you have a UIScrollView with mainly text, then add a couple of views on top of it in order to add an effect to the text, should this change any of the gestures, or smoothness of the original UIScrollView without the subViews? Thanks.
It won't change the gestures.
As for the smoothness, it depends on how heavy your subviews are. I guess that if you add a lot of them, and they require to render a lot of dynamic content and such, it could make the scrolling a little rough, but if you are adding only a few subviews you should be fine.
As a comparison, think that a UITableView is a UIScrollView with a LOT of subviews on it (each cell is a subview, and cells have several subviews too), and it usually renders fast.
If the sub views you implement have the worst drawRect: implementation in the world, you don't need very many views to get slow, un-smooth scrolling.
You should profile your code in Instruments with the Time Profiler, and see what causes the slow scrolling.

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..

Movement of UIButton which is in the UIScrollview becomes slow after pinching/zooming out

I have UIButtons in UIScrollview and also UIScrollview contains Imageview too. If i move UIButtons, particular area of the image within that UIButtons arranged will be colored..
Its happening well but my problem is movement of individual buttons are happening well If image is in normal size. and movement is getting delayed once after pinching or zooming..
Can anyone tell the reason why this is happening?
Thanks and Regards,
V.Karuna.
This kind of issue is usually down to the level of processing effort on the phone. Having to clip obscured views, and deal with transparency slows things down a lot. Make sure that you set everything you can to be opaque. This can make a massive difference. (opaque is a property of UIView therefore inherited by all controls, buttons etc)

UIScrollview with two images - Keeping 1 image zoomable and 1 image static (fixed size)

I have a UIView which contains a zoomable UIImageView and also another semitransparent UIView on top of that.
What I am trying to achieve is to be able to zoom the UIImageView while keeping the semitransparent view static and not zoomed.
If I add the semitransparent UIView on top of the UIImageView (which is added to the UIScrollView), everything zooms. However, if I add both as subviews to the base UIView, the touches only get tracked is the semitransparent UIView since its the last one added.
I do need control to reside first at the semitransparent UIView for the touches since I may want to resize the semitransparent view. However, I'd like to pass control of the touches to the UIScrollView if two fingers are used. Is there anyway for me to achieve this? The nextresponder doesn't seem to work. I also tried to use hittest in addition to subclassing UIWindow, but the base UIView needs to push/pop navigation controlling ability so I don't think I can subclass UIWindow to push onto the navigation stack.
Any help would be appreciated.
Thanks,
Winston
Hm.. you can try this hierarchy (possibly subclasses):
UIView (container)
> UIView (semitransparent overlay)
> UIScrollview
- UIView (zoomable content)
Like this, the overlay does not scale.
The tricky thing then is the user interaction on multiple layers. Its easy if there are areas in your overlay that should not detect user touches, for that you just set the UIView property 'userInteractionEnabled' to 'NO' for the view parts where touches should be 'forwarded' to the underlaying layers.
But if I get you right, you need something more complicated. You probably could set up some kind of master-touch-controller in the container UIView, that finds out what is happening and then calls certain methods of its subviews / forwards the events.
I don't know all the exact methods you need to override/implement in the container, but check out the tapZoom demo from the ScrollView Suite sample code. It's a pretty nice example there.
Just out of curiosity, may I ask what this interaction model is used for?