I have an UIScrollView. My most of the operations are on the zoom level of UIScrollView. I test using instruments, at normal zoom level (i.e 1) its taking less memory but when I zoom its taking too much memory and crashing also.
Detailed scenario:
I took UIView as subview of UIScrollView. I am drawing some shapes on it.
I have to show information in these shapes when the UIScrollView zoomed. So I am adding information view on UIScrollView when zoomed and remove it when zoomed out.
I need to know, whether UIScrollView takes more memory on zoom or my approach is wrong?
UIScrollView itself does not define drawRect: so it takes only small amount memory for storing its properties.
When zooming UIScrollView applies scale transform to the contents view returned from viewForZoomingInScrollView:. This does not change amount of memory consumed by the contents view, just changes its visible rectangle. So if your app crashes when zooming look at the code you execute when/after zooming.
Related
I'm making simple number coloring game (like sandbox, pixel art, unicorn, etc) and came across a problem. I tried various methods of filling rects in the screen.
At first i created a backgroundView(a simple UIView) which had 2500 subviews(also UIViews), each one had size = (CGSize){50,50}. Added a tap gesture recognizer, detected which view should be filled, and simply changed the background color of that view. But when i placed the backgroundView in the scrollView, the scroll and zooming were awful.
Tried same thing but this time each rectangle was a CALayer. So a backgroundView, which had 2500 sublayers(each was a CALayer with 50,50 size) - zoom and scroll was also awful.
Tired to use custom drawing with overriding drawRect method in UIView subclass or drawInContext in CALayer subclass(i was filling rects with CGContext), this time problem was also caused by the zooming and scrolling. Because i needed to update every rect when user zooms, it was triggering a lot of drawRect calls, and performance was also bad.
Any thoughts how can i fill rects in the screen ?
Explanation
Yup! Adding 2,500 tiny UIViews to a scroll view can destroy performance. I wouldn't use that approach, but if you do, at least make sure that subview_N.opaque = YES; on all subviews to disable compositing.
The CALayer approach that you described is basically the same as the UIView approach because views are backed by CoreAnimation layers (see -[UIView layer]).
The best options for drawing thousands of rectangles to the screen on iOS without decimating frame rate, is to use one of the following approaches:
Draw directly using CoreGraphics
Draw directly using OpenGL (extremely involved)
Use a layout engine such as UICollectionViewLayout
Now, you said you had tried overriding -[UIView drawRect:], but you didn't provide any example code for us to checkout. Please update your question with actual code for method #3 if you want more specific feedback. It's very likely that something is wrong with the drawRect code you created. CoreGraphics can definitely draw thousands of squares on screen without dragging frame rate down that badly.
One Solution
I recently released a project, YMTreeMap, that draws thousands of rectangles into a UIView to create financial TreeMaps. It's in Swift, not Objective-C, but the underlying concepts are the same. For this, I created a custom UICollectionViewLayout that lets Apple's well tested UICollectionView class handle the nitty gritty of selective drawing, zooming and animation.
The example UIViewController code in the YMTreeMap project shows how to draw thousands of colored rectangles to the screen if all you know is their location and size. This sounds like what you are doing. Since you're also scrolling and zooming, this solution might be perfect for you because UICollectionView has native support for both of those.
I am trying to figure out how to achieve this. I want to have a view centred on the screen that can be pinched for zoom in and zoom out but also be panned across the screen. One way I thought of trying to replicate this was to have a UIView within UIScrollView. Let's say the UIView is just a black square. The UIView will be the same size as the UIScrollView and always remain centred. When I pinch the UIView to zoom out, as it gets smaller and the UIScrollView will zoom in at the same rate. This allows space to pan. The UIView would of shrunk, remained centred and the UIScrollView's content area increased. Is this something that is possible? Is using a UIScrollView the wrong way to go about it?
Let's say I have a complex UIView, which is initially on the screen with quite small frame, let's say 80x80.
One of its subviews is an UIImageView displaying an image whose actual resolution is 1024x1024.
When the user tap the UIView i want the view to zoom in almost full screen so that the user can better see the image.
I know already how to scale a UIView to zoom in, my question is the following.
What's the best way to zoom in this view without pixellating the image?
I thought of these options:
I can actually set the frame of the UIView to the full screen size, and normally scale it down, so I'm sure that when it's zoomed in, it will be perfectly detailed. This solution anyway have a strong performance issue, cause moving around many of these scaled down views, will be quite an hit on the CPU/GPU.
I can do it just as I described, so small frame and scale > 1 to zoom in, but in this case will the image be displayed without pixellating?
I can actually set the frame to redisplay the view at the big/small size. In this case the detail will be good, but I have a performance hit here too, because my UIView have around 15 subviews that need complex calculation to relayout, so it's not so "fast" to set the frame.
Which is the best solution? Or do anybody have any other better solution?
Why dont you just have thumbnail representations that are 80x80, and when the user taps on any thumbnail, you transition from your current view containing all the thumbnails to a new view with the +transitionFromView:toView:duration:options:completion: method and simply display a UIImageView with the full resolution image loaded into that new view :)
I want to zoom a CAlayer placed on UIView, and this view is on UISCrollview. I'm using scrollviews delegate methods for zooming. It zooms but it blurs. How to remove blur and improve zooming?
I have tried with CATiledLayer but I don't want to show tiling effect. So how can I improve zooming using CALayer?
I had a similar experience when zooming in content. When a UIScrollView is zooming, it takes a snapshot of the View, and zooms in on that picture. This is the reason it gets blocky when zooming. When the zooming/panning is complete, use the delegate to re-render the content according to your zoom level. The content then should be 'crisp'.
Warning: do not zoom in too far, the memory used by the snapshot will soon be larger than your available memory.
I didn't use images, but CAShapeLayers and paths. I put together a demo project and explanation here : http://simplicate.weebly.com/1/post/2013/06/fixing-blocky-paths-in-ios.html
I hope that helps.
I'm making a music app that displays musical notation. Currently the notation is in a very large view that extends horizontally until the music ends. Obviously this isn't a good solution because I quickly run out of memory when display large scores of music.
My question is how I can implement my view such that the view where I do my drawing is only the size of the screen, but the content gets scrolled across it (The view is contained in a scrollview)? I imagine I could just only draw stuff on the screen and redraw the view as it gets scrolled with different x coordinates, but this seems ugly and would be pretty slow.
Thanks for any suggestions. : )
There are a number of solutions around. Usually these involve drawing one-or-two screen widths past the edges, then scrolling as needed, and drawing again into the area that was previously visible. In essence, using the scroll-view as a circular buffer.
Try a Google search for UIScrollView infinite scroll.
Also, see Infinite horizontal scrolling UIScrollView.