Swift/ios wave fill animation inside custom layer/shape - ios

I am trying to achieve a fill animation similar to the GIF below but inside a non circular boundary similar to the second image. Can this be done over a UIImage of just the drop?

Sure, you could do that with a CAShapeLayer where you animate the path that draws the shape. You'd then add a mask layer to the shape layer that masks it to the shape of the drop, (which would be another shape layer in the shape of your drop.)
You should be able to get the shape of the wave with a single cubic bezier curve, as wide as the widest part of the area you're filling. You'd create a closed shape that was your wave curve, then the sides and bottom of a rectangle to create a closed shape.
For the wave animation I would suggest a closed UIBezierPath that is 3 sides of a rectangle, followed by a cubic bezier curve who's start and end where on the top corners of your rectangle, and the middle two control points were at 1/4 and 3/4 of the way along the rectangle in the X dimension. Make one of those control points above the top line of your box, and the other below the top line. The animation would just be switching the Y positions of the 2 middle control points of the bezier curve.
Here is what the shape looks like in Photoshop:
Make that bezier path wider than your drop shape, so the ends of the top curve that don't move are out of view.
You'd install the CGPath of that bezier path into a CAShapeLayer. You'd then add a repeating, auto-reversing CABasicAnimation to the shape layer that would swap the Y positions of the two middle control points of the top curve, so the wave peaks and troughs would switch.
Next, you'd create a second CAShapeLayer that would contain a closed drop shape, and install the drop shape layer as a mask on the wave layer.
Finally, as you change your slider, you'd shift the Y position of your entire wave shape layer up and down.

Related

UIBezierPath combine shapes

This is not asking the same question as How can I combine UIBezierPath drawings? even though the name is similar
I have a shape that needs to be able to scale vertically and on one side of it are rounded corners and the other side is some other path. I have drawn the following image to show what I am talking about, but this is not the exact shape I am making, but conceptually it is the same idea.
In this image, the left side is half of a rounded rectangle and the right side is half of a circle.
So I am wanting to take and essentially cut a rounded rectangle in half and basically "merge" it with another path. How can I do this?
I guess one way would be to have two layers: the top layer contains the shape on the right and the bottom layer contains the rounded rectangle, and the top layer occludes half of the rectangle. But I was hoping to not have to use two different layers, and instead be able to put all of this in one layer, so I was wondering if it was possible to merge the shapes like I mentioned.

Swift 3, draw circle with special lineCap

Currently I'm using CAShapeLayer and UIBezierPath to draw a line for avatar. It's Ok for the normal one with lineCap = kCALineCapRound. BUT I've been STRUGGLING to draw line with START and END lineCap like image below:
You can't draw this circle with a shape layer, because a shape layer supports only one single stroke color. You should write your own layer class where you should draw three separate circle segments with kCALineCapRound:
A full yellow circle.
Draw the blue segment over the yellow circle. It is visible and you can see the rounded ends.
Draw a segment of the yellow circle, say 5 degrees of the top. Then you can also see the rounded end of the yellow line.
You should use CGPath and CGContext instead of UIBezierPath.

CAGradientLayer with Angle

I am drawing CGPath which is not rectangle or square,and adding CGPath to CAShapeLayer. This CAShapeLayer's frame getting from CGPath using CGPathGetBoundingBox(path). So it will be rectangle or square. Now i want to set gradient color to layer but my path is not rectangle or square so it is not spreading gradient color equally in whole CGPath. Is there any way to set gradient color to CGPath or how can i set gradient color with angle?
Please refer screen shot to understand situation. Here white color indicates frame of CGPath and green colour, that is our drawn CGPath. At the bottom of CGPath you can see white gradient colour which is not distributed equally in CGPath.
The start and end points of a linear gradient are specified in points relative to the whole size of the layer, with (0,0) at the top left and (1,1) at the bottom right.
Therefore, to make a linear gradient at an angle, you simply need to set the start and end points appropriately. For example, If you used (0,0) and (1,1) as the start and end points, the gradient would run from the top left to the bottom right, at a 45 degree angle.
Working out the specific start and end points for your needs is therefore just a matter of trigonometry.

Common outline for two shapes drawn in drawRect: ObjectiveC

I have two shapes in a UIView - one, an ellipse and two, a triangle drawn using UIBezierPath. I need to draw the outline of these two shapes combined. How can I do it?
You can do an "outside" stroke (like stroke->outside in photoshop/pixelmator) by calling stroke to draw the outline and setting the inverse of your shapes as the clipping path first. To do the inverse of the clipping path see this answer: https://stackoverflow.com/a/10639523/461492 (read comments too).
So here are the steps:
Set the full area as the clipping path.
Call CGContextEOClip() for each of your shapes as described in the comments to the answer linked above.
Stroke your shapes.
This might not be exactly what you want - it will draw the stroke as normal but the whole interior (the fill area) of your shapes will not be drawn. So whereas the thickness of the stroke would normally extend within the interior of your shapes, and the internal angles of your stroke would normally have the correct corners (rounded/mitered) - in this case it would be more like you stroked the shapes then deleted the fill-area, or did an "outside" stroke in an image editing program.

How to animate arc/donut segment stroke and length change

I need to animate arcs (a.k.a donut segments) in the following scenarios where the arc maintains a constant radius r to the imaginary circle center (the arc sits right outside the circle).
1) Animate the arc stroke width from x to y, while maintaining a radius r and angle alpha.
2) Animate the arc angle from alpha to beta while maintaining a constant stroke width and radius.
3) do 1 and 2 together but possibly with independent animations/timings.
Here's what I have so far:
I’ve implemented the arc drawing as a custom view that simply draws the arc with CGContextAddArc. This is fine for a static arc but it doesn’t animate anything.
Also, I know how to draw clipped images with things like [UIBezierPath addClip].
The latter is interesting because I think that for scenario 1, I can achieve the desired effect in two ways: either keep drawing an arc and modify both stroke and radius to maintain the same perceived inner circle radius (which I’m not optimistic about, I’m afraid that the radius will “jiggle”), or draw a segment of a circle that grows in size (maybe by simply modifying the scale with an affine transform) and is then clipped by a static circular mask.
Now, how do I take all these concepts and nail them down into some actual drawing code? I don’t need real code (though that would be fine too), but more like a conceptual approach, like, can I do this all with a UIView with custom drawing, or do we need to talk about custom key animations that I understand involve CALayers and such. In other words, what’s the right architecture to do all this that would be easiest to code while being efficient from a compositing perspective for smooth animation?
You can already do this with a CAShapeLayer by creating the path for the arc and then animate different stroke properties. You could create the path for the full circle and use the strokeStart and strokeEnd properties to only stroke a certain part of the circle. It is worth noting that the shape layer is center stroked so they increase equally inwards and outwards as you increase the line width. To counter this you could either mask it with the same circle shape and double the line width or animate the path so that the radius increases by half of the line width increase so that the inner most point has the same distance to the center at all times.
The first example can be done by animating the lineWidth property and the second can be done by animating the strokeStart and strokeEnd properties
You should implement this using custom animatable properties on a CALayer subclass. This tutorial (with source here) is for creating animated pie charts and looks pretty good. You should be able to modify it for your requirements.

Resources