Avoiding UIView to create a very large drawing canvas

I got a class from UIView, only to understand that there are real limitations on its size due to memory. I have this UIView inside a UIScrollView.

Is there a way to place something inside a scroll that is not derived from UIView, but which I can still draw into, and which can be very large?

I do not mind responding to open-rectangle events, as is done with conventional window systems.

Thanks.

+6
source share
2 answers

Things inside a UIScrollView should be UIViews that are limited in size for memory reasons. UIView supports raster backup storage for performance reasons, so it should allocate memory proportionally to its size.

The usual way to handle this is to create multiple UIViews and replace them when the user scrolls. Another version is to use CATiledLayer . However, none of them gives you a model for drawing a "giant canvas." It is for you to break things up and draw them as needed. This is a common approach.

If you really want a giant canvas, my recommendation would be CGPDFContext . There is a lot of support for them, especially with the UIWebView (remember that you can open the URI data: to not read files from disk). And you can draw parts of them directly using affine transforms and then CGContextDrawPDFPage . CGBitmapContext is a different approach, but for a small number of drawings, much more memory may be required.

+5
source

So, you have a UIView inside a UIScrollView , but you want your UIView have very large borders (i.e. it matches the size of your UIScrollView contentSize ). But you do not want to draw the entire UIView every time it should be displayed, and you cannot completely place all its contents in memory.

Make your UIView using CAScrollLayer as follows:

 // MyCustomUIView.m + (Class) layerClass { return [CAScrollLayer class]; } 

Add a method to update the scroll position when the user scrolls the UIScrollView containing your UIView :

 // MyCustomUIView.m - (void) setScrollOffset:(CGPoint)scrollOffset { CAScrollLayer *scrollLayer = (CAScrollLayer*)self.layer; [scrollLayer scrollToPoint:scrollOffset]; } 

Make sure that when drawing the UIView you only draw the parts contained in the CGRect provided to you:

 - (void)drawRect:(CGRect)rect { // Only draw stuff that lies inside 'rect' // CGRectIntersection might be handy here! } 

Now, in your UIScrollViewDelegate , you will need to notify your supported CAScrollLayer when updating the parent UIScrollView :

 // SomeUIScrollViewDelegate.m - (void) scrollViewDidScroll:(UIScrollView *)scrollView { // Offset myCustomView within the scrollview so that it is always visible myCustomView.frame = CGRectMake(scrollView.contentOffset.x, scrollView.contentOffset.y, scrollView.bounds.size.width, scrollView.bounds.size.height); // "Scroll" myCustomView so that the correct portion is rendered [myCustomView setScrollOffset:self.contentOffset]; // Tell it to update its display [myCustomView setNeedsDisplay]; } 

You can also use CATiledLayer , which is easier because you do not need to track the scroll position, instead, your drawRect method will be called with each tile as needed. However, this will make your view slowly fade. Perhaps it would be advisable if you intend to cache parts of your view and are not against slow updates.

+2
source

Source: https://habr.com/ru/post/895971/


All Articles