CALayer won't redraw - objective-c

I have an NSBox containing a hierarchy of layer-backed views. If i add a subview to the NSBox and add gaussian-blur to the background filters (which works perfectly) and then remove the view again, the layer seem to stick around and keeping the drawing, or the hierarchy's layer may keep the information. I can't figure out how to reset/redraw/what-ever-it-takes to remove this "burned in" image.
I'm very new to Core-Animation and Quartz so it might very well be straight forward but I can't get my head around it.
Edit: The problem only exists when a CALayer above a SourceList was blurred and transparency is on (OS X Yosemite). If transparency is off there's no issue.
(Sorry for the red lines)

Related

Completely transparent UIButton with irregular hit area

I know how to use a background image with alpha channel to create a UIButton with an irregular tap area. But with this solution, only the ignore-tap area is transparent; the tap area consists of the opaque.
What I want is a totally transparent UIButton, with an irregular tap area. (It triggers an animation behind the button.)
It seems that some sort of extra UILayer with some hit-testing could work, but I don't quite see how. Suggestions welcome.
Here's my solution. The problem: A UIImageView (call it the base view) to which I want to attach an irregularly-shaped tap area. The area corresponds to something in the image, let's call it a river. It could be a non-connected region.
In the Finder, duplicate the view's image, and make all the non-river pixels transparent, using your favorite graphics app. Call this the mask image.
When the base view is tapped, check to see if the corresponding pixel in the mask image is or is not transparent. (Solution left to reader; examples abound.)
So the mask image is never actually rendered, it is just used as a reference.
Note that if the base view gets resized or moved around (as it does in my app, via animating its constraints) then you have to "move" the mask image too, or in some other way manage the coordinate translation between view and mask. The easiest way to do this is to make the mask image a hidden subview of the base view, with its left, top, leading and trailing anchors constrained to be equal to those of the base view. Then they move around together, and the coord translation between the two is the identity.
I wrapped all this up in a subclass of UIImageView so that it manages its own mask, and calls a delegate if the "river" (or whatever) is tapped.

Too many UIViews causes lag

I am creating an app for practice that is a simple drawing app. The user drags his/her finger along the screen and it colors in a 100px x 100px square.
I currently achieve this by creating a new colored UIView where the user taps, and that is working. But, after a little time coloring in, there is substantial lag, which I believe is down to there being too many UIViews as a subview of the main view.
How can I, and others who similarly create UIViews on dragging a finger reduce the lag to none at all, no matter how many UIViews there are. I also think that perhaps this is an impossible task, so how else can someone like me color a cube of the size stated above in the main view on a finger dragged along the screen?
I know that this may seem like a specific question, but I believe that it could help others understand how to reduce lag if there are a very large amount of UIViews where a less performance reducing option is available.
One approach is to draw each square into an image and display that image, rather than keeping around an UIView for each square.
If your drawing is simple enough, though, you can use OpenGL to do this, which is much faster. You should look at Apple's GL Paint Sample Code which shows how to do this in OpenGL.
If your drawing is too complex for OpenGL, you could create, for example, a CGBitmapContext, and draw each square into that context when the user drags their finger. Whenever you draw a new square into that bitmap, you can turn the bitmap into an image (via CGBitmapConxtextCreateImage) and display that image an a UIImageView.
There are two things that come to my mind:
1- Use Instruments tool to check if you are leaking any memory
2- If you are just coloring the views than instead of creating images for each of them, either set the background color property of UIView or override the drawRect method to do custom drawing
I think what you are looking for is the drawRect: method of UIView. You could create your custom UIView (you propably have that already) and override the drawRect method and do your drawing there! You will have to save your drawings in an array or another container and call the setNeedsDisplay method whenever the array content is changed.

Stacking UIViews with blend modes in iOS

I have two different UIImageViews. I'd like to make the top UIImageView blend in using the Screen blend mode with the bottom UIImageView.
I know of the property of CALayer: compositingFilter and I know that it doesn't work in iOS. I've searched a lot for solutions, and I've found how one should subclass UIView and override drawRect.
I've tried to set the context in drawRect to the screen blend mode, although it still draws every one of the images normally. Perhaps I am doing something wrong, or the approach should be different. Maybe I need OpenGL or CALayer to achieve this. Could someone assist?
Unfortunately there is no way to do a non-composite blend between UIViews on iOS. UIKit doesn't provide the functionality, and you've already noted, CALayer can't do it either.
In general, implementing -drawRect in a UIView won't help you. You're drawing into an empty bitmap -- it doesn't contain the bits of the views behind it, since those might change at any time (any view or layer might be animated). CA fundamentally assumes that layers' contents should be independent of each other.
You could try, in your -drawRect:
create an image context
capture the views under your view using -[CALayer renderInContext:] for each
create an image from the image context
draw that image into your view
set the blend mode and draw on top of that
But that will be slow and fragile, and won't work if you animate any of the views. I wouldn't recommend it.
If you really need to do this, you're going to have to switch your whole scene to render with OpenGL, where you've got more freedom.

Best approach for drawing a graph of almost infinite size in a UIScrollView on iPad

I'm currently working on an app which needs to draw s.th. like a network graph. Unfortunately this graph can become very big with thousands of movable objects.
I tried to put a giant UIView inside a UIScrollView but soon noticed this won't work because of memory limitations.
So I tried another approach: currently I have a UIView which has exactly the size of the visible part of the UIScrollView. The scrollview is set to not handle the scrolling (only the pinching). Instead I handle the scrolling in the UIView. Everytime a user scrolls, all graphic objects (those graphic objects are currently just subclasses of NSObject, which contain custom drawing code) are moved, so it seems like the view is scrolling. In the drawRect I only draw the graphics that are currently visible.
Also I constantly add and remove sublayers if they are moved out/in the visible frame
This works very smooth even with thousands of objects.
Unfortunately this approach has some drawbacks:
I can't zoom out to see all the objects in the graph, instead the user can only see a part of it
I don't get the inertial scrolling the UIScrollView offers
Other approaches I tried, like the CATiledLayer, don't work either because all the objects in the graph are draggable by the user and it looks really ugly if I use a CATiledLayer...
Swapping out the UIView with other UIViews while the user scrolls may help with the inertial scrolling, but it makes everything more complicated and zooming out completely still won't work :-(
Do you know of any best practices to draw graphs that can be very big?
//edit: I ended up with a uiscrollview which has a subview which has a cascrolllayer which has many sublayers. While zooming in and out the frame of the uiscrollviews subview is constantly changed to the uiscrollviews bounds by view.frame = scrollview.bounds. While dragging the scrollview the cascrolllayer is always forced to scroll to the current offset of the scrollview.
I needed to subclass the uiscrollview and hack around in order to make the zooming work nicely, but it's working well now. This approach works very well and allows very big graphs with lots of draggable elements.
//edit: see my other answer below, the approach above didn't work out as well as I initially thought, especially the zooming part
CATiledLayer is definitely what you should use here—there’s not really another solution that’ll let you use Quartz/UIKit drawing on a huge zoomable canvas. For anything that needs to be interactive (dragged or animated or whatever), you can disable its display in the main tiled layer and overlay another view or layer on top of it that just contains the object being interacted with.

Resizing an NSView smaller than its subviews?

Couldn't find anything on the net about this and wondered if anyone on SO has a solution.
I have an NSView with several subviews that are centered by removing the left and right anchor points. When I resize my view, programatically or with the mouse, to a smaller width than the subviews: it pushes them off center. Has anyone come across this before and do you have a solution?
EDIT: I want to be able to resize my view to a zero width. The reason being, the view is actually part of a split view and I have hooked up a button to 'collapse' it. When it collapses all of the subviews are pushed off-center and aren't re-centered when the view is resized, effectively un-collapsing it.
I have solved my problem now and thought I would share incase anyone comes across this issue in the future.
No amount of playing with autosizing options or view layouts in Interface Builder seemed to stop my subviews from getting moved off center. I did manage to find this link here and from this page, the advice:
Springs and struts, as currently
implemented, are really no good for
anything but keeping either one or
both sides of a view "stuck" to the
nearest edge. Any sort of centering
behavior, division of gained/lost area
between multiple views, etc. has to be
done by hand.
Based on this I overrode my view's setFrame: method and manually laid out my subviews using their setFrame: method. This works great and gives me the results I'm looking for.
There is the same issue using NSSplitView, resizing here one Subview to be smaller than the Subview Subviews makes sense,e.g. having small charts in the upper subview, and an rss reader in the lower subview.
If you want to show only the rss reader in the lower subview, you can "hide" the upper subview, but after resizing the upper subview the NSImageView are not layed out the same as in the beginning. Check this nib/xCode Project and the following screenshot to see this behaviour.
Only workaroung is to override the resize function to stop getting smaller.