I created a minesweeper clone game in iphone. My implementaion of the cells in the grid is this, I created a UIView and added buttons in the UIView and then I added the UIView in a UIScrollView, but every time I zoom out or zoom in using zoomToRect method of UIScrollView the zooming is not smooth and the zoom out was distorted. How can implement smooth zooming in UIScrollView?
I would try rendering your content view into a bitmap image when scrolling or zooming begins, and replacing the large grid of buttons with the bitmap until the scrolling/zooming is completed. The UIScrollViewDelegate protocol should provide you with the necessary information to know when to swap the bitmap in or out. Part of the problem is that your content view is so computationally intensive to render (all those buttons).
A more sophisticated approach would be to re-implement your game grid at a lower level using coreanimation and more fundamental touch event handling, but that might be overkill if the bitmap hack works well enough.
You know how in the maps app, while panning or zooming, there are grey tiles that show up? That means that the iPhone is currently downloading the tiles. In Safari, there is a similar effect where Safari lays down checkered grey instead of webpage, as it is currently rendering it and will be just a moment. Both of these mean that scrolling will not wait for content to load before displaying the area, it will let scrolling be smooth.
You could try looking here [http://stackoverflow.com/questions/1098234/optimized-image-loading-in-a-uiscrollview] for some ideas, and a point in the right direction would be to use threading to load views in the background while displaying grey in its place.
Related
Too much code to post here easily, so I thought I just try and check if I am in fact attempting the impossible first.
I have a scrollView which I can pan and zoom within, it works well. I am also drawing into a layer of a UIView that I add as a subview of the said scrollView.
Everything looked as if it was working, but I have just noticed a small snag.
I draw into the layer and I can pan around my image and drawing moves too. All good.
But when I zoom into my image, the image gets bigger... but the drawing remains the same size... which isn't really what I wanted to happen. I wanted the drawing to zoom in too.
Is the normal behaviour?
I am creating a graphing calculator application in OpenGL on iOS, and I would like to implement pinch zooming that works like the google maps application or uiscrollview zooming. I'm pretty sure I can't use a uiscrollview because the content of the graph is being generated dynamically.
Implementing zooming where the center of the screen is assumed to be the center of the zoom is easy, but in other cases it is not obvious to me how its being implemented. Can anyone point me in the right direction?
The view that does your custom drawing should be capable of drawing at a certain scale. When your user zooms in or out of the scroll view, send the appropriate zoom factor and let the view redraw itself. The changing bounds is not a problem. The scroll view adjusts its bounds as you pan inside, so its subviews shouldn't have any concern over the bounds of the scroll view.
Of course, you'll probably have to consider performance. For example, it may be too slow to redraw the graph at every frame as a user zooms. Instead, you may only want to redraw when the user stops zooming, which is what Maps.app does.
There are many other considerations for this problem, but that would be where I would start.
EDIT: Ah, I overlooked the OpenGL aspect. Still, with a GL layer-backed view, you still should be able to make the appropriate translations based on both the current zoom factor as well as the scroll view's bounds.
I am creating a navigation based application, and throughout my application, I want to maintain an image as background. Also, I want parallax scrolling for the background, i.e., when I scroll table view cells vertically, background image should scroll at a relatively slower speed. Also, my application has some images and text in detail views, which should scroll at higher speed and background at a lower speed. This I want is to create a 3D effect. I have gone through cocos2D framework, but its all apps shows a single view and two images, one for foreground and one for background. So I need some starting point, whether I am in right direction or not. Also, is it possible without using cocos2D? Please help me for this.
Thanks in advance.
Try to use the - (void)scrollViewDidScroll:(UIScrollView *)scrollView of UIScrollViewDelegate.
The table view is a sub-class of UIScrollView.
I created UIScrollView and added UIView with lots of tiled UIButtons in the UIView. My problem is, when every time I zoom out the content using zoomToRect method of UIScrollView to the minimum scale I set, the zooming out is not smooth. But zoom-in and zoom-out for the second time is smooth. How can I make the zooming out for the first time to smooth zooming?
Thanks.
The slow initial zoom is obviously due to the phone allocating all the UIButtons the first time it has to draw them. They should be allocated incrementally or before the user starts to interact with them.
What are you doing that requires so much loading and drawing? It doesn't sound like the user would be able to interact with the million or so buttons they might be viewing.
I would suggest adding a pile of code to a UIScrollView Sub Class that makes it aware of it's content size, and it can then init the required UIButtons before the user starts to interact with your UIScrollview, or incrementally as I said.
There is demo code called 'Tiling' that sheds some light on using UIScrollViews to manage large content. It's quite complex, but a very complete demo that I'm sure most projects implement if they handle UIScrollViews with tiled content.
Before zoom out set your UIScrollView* scrollView like:
scrollView.contentInset = UIEdgeInsetsMake(0,0,0,0);
All,
I'm having trouble getting behavior that I want from CATiledLayer. Is there a way that I can trigger the tiles to redraw without having the side-effect that their areas are cleared to white first? I've already subclassed CATiledLayer to set fadeDuration to return 0.
To be more specific, here are the details of what I'm seeing and what I'm trying to achieve:
I have a UIScrollView with a big content size...~12000x800. Its content view is a UIView backed by a CATiledLayer.
The UIView is rendered with a lot of custom-drawn lines
Everything works fine, but the contents of the UIView sometimes change. When that happens, I'd like to redraw the tiles as seamlessly as possible. When I use setNeedsDisplay on the view, the tiles redraw but they are first cleared to white and there's a fraction-of-a-second delay before the new content is drawn. I've already subclassed CATiledLayer so that fadeDuration is set to 0.
The behavior that I want seems like it should be possible...when you zoom in on the scrollview and the content gets redrawn at a higher resolution, there's no blanking before the redraw; the new content is drawn right on top of the old one. That's what I'm looking for.
Thanks; I appreciate your ideas.
Update:
Just to follow up - I realized that the tiles weren't being cleared to white before the redraw, they're being taken out entirely; the white that I was seeing is the color of the view that's beneath my CATiledLayer-backed view.
As a quick hack/fix, I put a UIImageView beneath the UIScrollView, and before triggering a redraw of the CATiledLayer-backed view I render its visible section into the UIImageView and let it show. This smooths out the redraw significantly.
If anyone has a better solution, like keeping the redraw-targeted tiles from going away before being redrawn in the first place, I'd still love to hear it.
I've found that if you set levelsOfDetailBias and levelsOfDetail both to the same value (2 in my case), then it only redraws the tiles that are touched by my setNeedsDisplayInRect: call, as you'd hope.
However if the levelsOfDetail is different to LODB, then any calls to setNeedsDisplayInRect: redraw all the tiles.
You could add another layer (possibly a CATiledLayer) behind the existing tiled layer. (Sort of a double-buffered solution.) You would call setNeedsDisplay: on the second layer from a timer that fires after a few seconds to ensure that that layer doesn't redraw at the same time as the front layer.
Another potential option is to use the same delegate to draw content to a bitmap context and swap the bitmap into the backing store once the content is refreshed. This should produce a flicker-free result. That being said, I can't tell you how this might be done, and one nice thing about CATiledLayers is they automatically generate tiles when you zoom and pregenerate tiles when you pan once zoomed in.
I would like to see how you implement your application. I have been looking for weeks to find an example that uses a combination of UIScrollView and a CATiledLayer-back view with a lot of custom drawn lines. Apple has some great sample code - but it all involves images rather than line art, so no help for me.
Having read through these answers without a solution, I discovered that tiling a page was the dominant background task.
Preparing my lo-res placeholder image on a high priority queue solved this issue - the images now appear while the tiling is occurring. Caching the placeholder images further improves their appearance - they appear before the tiling begins.
With newer devices, the tiling it so fast, these tricks might not matter. A sample PDF consisting of large scanned images (e.g. a scanned book) tiles the slowest in my experience, and makes for good test data.
I had the same problem with iPad.
The solution was more simple than I thought and far more simple than using UIImageView to render display before redrawing... :
Just don't set any background color for the Layer!
I had CATiledLayer set in a similar way:
layer = [[CATiledLayer alloc] init];
layer.masksToBounds = YES;
layer.contentsGravity = kCAGravityLeft;
//layer.backgroundColor = [[UIColor whiteColor] CGColor];
layer.tileSize = CGSizeMake(1004.0, 1004.0);
layer.levelsOfDetail = 16;
layer.levelsOfDetailBias = 8;
Note that I have commented out the line setting layer's background color to white.
After that the white blank before redraw problem disappeared!
Let me know if anyone has tried that.