Difference between masking a layer and adding sublayer iOS - ios

Want to understand exact difference between masking any layer and adding a layer as sublayer. I have searched and found some answers but not able to understand it correctly.
Something I found like masking causes offscreen rendering but adding a sublayer doesn't so can't we just use addsublayer?
Here I found something but not getting this so if there is any example of this would help more
More specific : Lets have a layer say layer1 now I want to understand difference between following :
addSublayer(layer1)
mask = layer1
We know here that both are applied using main layer of our UIView like view.layer

Layer - is a "next view on super view", but sublayer is a "next layer on super layer".
Hierarhy:
View(Super) -> has view(super) -> has layers(super): [layer1, layer2, etc] ->
layer1(super) -> has sublayers(super) [sublayer1, sublayer2, etc].
sublayers - endpoint in hierarhy.
a view can have more layers. layer can have more sublayers. but sublayer cant have other sublayers.
// sorry for my english :)

If I understand this correctly, the layer is added on top of the view whereas the mask is a subtraction of the current layer.
If you have a gradient layer add it to the view it will follow the gradient direction specified lets say from the bottom to top. But if you add the same gradient as a mask, you would be subtracting the layer and therefore it would like the gradient comes from the top to the bottom. Also you can use masks to cut shapes in images. They are very similar though.

Related

How to Change Color of UIBezierPath Stroke Whilst Animating?

I was wondering if it was possible to change the color of a UIBezierPath strokeColor while its animating. For instance, if it goes past a certain angle like 45 deg, it changes from green to orange, and if it goes past 66 deg it goes from orange to red.
Somebody else suggested using a "gradual" (gradient) layer. If you can create a gradient that meets your needs then that would work.
You could do just about anything you want by creating an image that contains the colors you want, and then installing a shape layer as a mask layer to that image's layer, and animating changes to the path installed in the shape layer.
I've used a technique like that to create various sorts of "wipe" transitions that reveal an image. See the thread below for info and working code showing how to create a "Clock wipe", which is almost exactly what you need:
How do you achieve a "clock wipe"/ radial wipe effect in iOS?

Smootly mooving a hole in UIImage?

I have a UIImageView displaing an image. This view's layer is masked with CAShapeLayer in order to create circular "hole" in the image. To create the hole I use UIBezierPath with .usesEvenOddFillRule = true.
It works fine when static. But I need that hole to move with user finger. To do that I create new UIBezierPath with even-odd rule each time user moves their finger. On smaller phones with smaller images it looks OK but on iPhone 6 Plus it is choppy.
Any ideas on how to make it smooth are very wellcome. I cannot just move the frame of masking CAShapeLayer - it would move the hole bot also hide some edges of the image. So the only way is to change its .path each time user moves finger and that is slow.
EDIT: matt's answer would work in some scenarios but not in my case: I am not displaying the whole image only a part of it defined by UIBezierPath. This part is most often oval (but can be rectangular or rounded rectangle) and it has "hole" cut in it. While the hole is mowing with users finger the displayed part/shape of the image does not change - it is static.
The ineficient solution that was in place so far wa:
Create UIBezierPath with boundary of displayed part of the image
Set 'even off fill rule' on it
Add UIBezierPath of the hole to it
Set it as path of CAShapeLayer with some opaque fill color
Use that CAShapeLayer as mask of the UIImageView
This procedure was repeated each time a user moved their finger. I cannot simply move the whole mask layer as that would also change the part of the image being displayed. I what it to stay static and move only the hole in it.
it would move the hole bot also hide some edges of the image
Well, I don't agree. Moving the mask is exactly the way to do this. I don't see why you think there's a problem with that. Perhaps the issue is merely that you have not made the mask layer big enough. It does not have to be the same size as the layer it is masking. In this case, it needs to be about 9 times the size of the masked layer (3 horizontal and 3 vertical), so that it will continue to cover the masked the layer no matter how far in any direction the user slides it.

iOS Understanding Layer Masking

I am having some difficulty understanding on how layer masking works. Right now, I have a UIView with UILabels on it. I picture two layers - one with the UIView in the back and one for the labels on top. If I mask the UIView layer, the labels will be affected by the mask too.
The UILabels are children of the parent UIView, so I can understand a parent mask affecting the children as well.
However, when I look at it in terms of layers, it doesn't seem to make sense. Why does masking the deepest layer affect those on top?
Think of layers as sheets of paper. Think of the view's layer as a big sheet of white paper. As you figured out, the labels' layers are children of the view's layers. To relate, think of the labels' layers being strips of paper glued onto the big view's layer-sheet.
Let's say you wish to mask the layer with a circle. To translate that into our little analogy, you wish to cover the big view's layer-sheet with Harry Potter's invisibility cloak, with a circle shaped hole in it.
To do that, you'd cut the invisibility cloak to the same size as that of your view's layer-sheet.
cloakLayer.frame = bigViewLayer.frame;
Then, you'd carefully cut out a circle from it.
cloakLayer.path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(0, 0) radius:15.0 startAngle:0.0 endAngle:2 * M_PI clockwise:YES];
cloakLayer.fillColor = [UIColor blackColor].CGColor; // the hole
Then, you'd paste this cloak-with-a-hole onto your big view's layer-sheet, carefully aligning the edges.
bigViewLayer.mask = cloakLayer;
What's gonna go invisible? Anything on the sheet (because the cloak was cut to the sheet's dimensions) that doesn't fall into the circle you removed from the cloak. That's the mask property.
Let's talk about the masksToBounds property.
Let's say while pasting the strips of label layer-sheets onto the big view's layer-sheet, you decided to place only half of the strip on the sheet, and made the rest hang off the edge(s).
Let's say you set masksToBounds to YES. What the gods of decoupage would do now is neatly cut off the parts of your labels' strips that are not within the edges of the big view's layer-sheet. That's the masksToBounds property.
Let's talk about borders. This is simple. Just pick a sharpie of borderColor whose nib is borderWidth points wide, and carefully draw on the edges of the view's layer-sheet. That's it.
I hope you get things now and can make your own analogies for other properties of the wonderful CALayer.
As you said, the UIView is the parent, and the UILabels are the children. When it comes time to update the screen, the UIView starts with a blank canvas. It draws itself into the canvas, and then has the children draw themselves into the canvas. When the children are drawing, they are subject to constraints imposed by the parent, e.g. clipping and masking.
iOS CALayer.mask
[CALayer]
[iOS CALayer.masksToBounds]
CALayer has a mask property which is CALayer, which applies mask's alpha channel to mask parent's layer.
layer + mask = masked layer

Creating animated image masking

I have a circular UIView. I want to be able to apply a mask that sits on top of it, and rotates above it so that the circular view appears gradually.
Is this even possible in iOS? I know it is in flast. But not sure where would I even start with a task like this in iOS??
You can create a shape layer like in this answer that will look as if it is appearing gradually (like a clock making a full circle). Then you can put the circular content in another layer (or use your view's layer) and make the shape layer the mask:
CAShapeLayer *maskLayer = // see linked answer
yourCircularView.layer.mask = maskLayer;
CABasicAnimation *drawMaskAnimation = // see linked answer
[maskLayer addAnimation:drawMaskAnimation forKey:#"appear gradually"];];
All UIView is backed by CALayer which allows some of the properties to be animated as well as mask to be applied. You will find the tutorial in this page very helpful. www.raywenderlich.com

How to apply 3d perspective transform only in one part of compound UIView?

I have UIView with UIImageViews, UILabels, UITextView.
My goal is to transform the middle part so it would look like folding a piece of paper:
- top and bottom parts remain the same only they slide towards eachother
- middle part folds towards the screen
(as in Clear app: http://blog.massivehealth.com/post/18563684407/clear?cbe4fc38)
My idea was to first load whole view, then split into 4 parts, make middle two parts into CGImage and somehow animate them with perspective while simultaneously transforming top and bottom parts, so they slide towards eachother (in the end, middle two parts should become invisible).
I also should be able to unfold this view and scroll UITextView.
I'm not looking for a ready-to-go answer, just pointers towards correct solution.
I have came across CALayer, CABasicAnimation and CGImage, but yet don't know how to solve this one.
I think your approach is sound. Since you cannot apply a transform to part of a view, you have to split your container view into separate parts. You can use the CALayer method renderInContext: to render a view into a static image. You can then split this image into the parts you need, place the image parts over the original view (or replace the view with the image) and animate the images. When the animation has finished, reinstate the view in its new form.
A few pointers:
convert your UIView into an image: see this post; either you take 4 "snapshots" of your view, or:
1.2 you take one, then crop the resulting image (see here for cropping);
create a new view and add 4 CALayers as sublayers of self.layer; each layer has its contents property set to the corresponding UIImage;
animate the view layers as you need; have a look at this file from the Leaves framework to see how this could be done; basically, this code uses a CATransaction and transformations to animate a property of the layers (which in this case represents the position of one layer respect another), so that when that property value changes, the layers are redrawn accordingly.
Hope it helps.

Resources