I have a CAShapelayer that's made from a bezier path, but the path is complex and not just a square.
I need to animate the shapelayer fill color to Yellow starting from the bottom of the curve and up (over y axis). (after the layer already attached with the path)
here is the path and layer curve:
If I use this code, it will animate all of the area at once.
let animation = CABasicAnimation(keyPath: "fillColor")
animation.fromValue = UIColor.white.cgColor
animation.toValue = curveFillColor!.cgColor
animation.duration = 4
animation.fillMode = .forwards
animation.isRemovedOnCompletion=false
shapeLayer.add(animation, forKey: "fillColor")
Shape layer code is :
let shapeLayer = CAShapeLayer()
shapeLayer.fillColor = UIColor.yellow.cgColor
shapeLayer.strokeColor = UIColor.yellow.cgColor
shapeLayer.lineWidth = 2.0
shapeLayer.lineJoin = CAShapeLayerLineJoin.round
shapeLayer.lineCap = CAShapeLayerLineCap.round
shapeLayer.strokeStart = 0
shapeLayer.path = path.cgPath
self.layer.addSublayer(shapeLayer)
I think you will probably have to create 2 versions of your shape layer: One filled using the starting color, and one filled with the ending color. Stack them on top of each other with the ending color layer on top. Then mask the ending color layer with a rectangular shape layer mask that has zero height. (meaning that the entire layer is masked.)
Now add an animation that animates the shape layer mask to the full height of your shape layer. That will reveal the ending color layer and cover the starting color layer, creating the effect that the ending color layer paints up from the bottom.
An alternative might be to rework your shape layer so that it that draws from the bottom to the top. To do that I guess you'd create a layer that was composed of a series of vertical lines drawn from bottom to top. Then you could animate the strokeStart or strokeEnd properties of your shape, but transforming your shape into a series of vertical lines would be a pain, and I don't know how you would do that for an arbitrary shape.
Related
hi i have a circle shapeLayer need color by GradientColor
i tried ues CAGradientLayer and mask it like this
let gradientChargeLayer = CAGradientLayer()
gradientChargeLayer.colors = CGColor.mColor
gradientChargeLayer.frame = vShape.bounds
gradientChargeLayer.locations = [0,1]
gradientChargeLayer.startPoint = CGPoint(x: 0,y: 0.5)
gradientChargeLayer.endPoint = CGPoint(x: 1,y: 0.5)
gradientChargeLayer.mask = shapeLayer
vShape.layer.addSublayer(gradientChargeLayer)
but what i want is gradient color from stroke start to end
shapeLayer.path = circularPath.cgPath
shapeLayer.strokeColor = UIColor.red.cgColor <<< here
thanks
you could’ve different approaches I believe
One, you could make an outer and inner circle and then add the required path/layer to the outer circle (this circle bigger than inner) both circles without visible stroke
Or I could recommend you UIGraphigsImageRenderer to work with
https://developer.apple.com/documentation/uikit/uigraphicsimagerenderer
This last have a context that could be used to do more advanced rendering context.cgContext.setStrokePattern here you can add a CGPattern and colors to trying accomplish it
PD. Sorry if my english is confuse
Shape layers only draw in a single color, as I guess you are aware.
By making your shape layer a mask onto a gradient layer you're able to have the shape layer reveal the color of the underlying gradient layer.
If you are always drawing a circle and want the color of the circle's stroke to vary from beginning to end you could set up your gradient layer using a type of conic, and specifying the colors in the gradient layer to begin and end where you want them. However, that would only work for shape layers that contain ovals, where the size and center of the shape and the size and the center of the gradient match.
As #Guillodacosta said in their answer, you may have to give up on using a shape layer and draw your graphic into a graphics context using Core Graphics. (You could do that once and capture the results into a UIImageView to avoid the slowdown of Core Graphics rendering.)
I am going to make 3D effect to uiview and add shadows like in the following image. there is white shadow on top and left sides and gray shadow on right and bottom side.
I already added white shadow on top and left sides.
my result
self.layer.shadowColor = UIColor.white.cgColor
self.layer.shadowOffset = CGSize(width: -4.0, height: -4.0)
self.layer.shadowRadius = 2.0
self.layer.shadowOpacity = 1.0
self.layer.masksToBounds = false
Is it possible to achieve the following result by uibezierPath?
Image
Try adding a creating another layer with the other shadow color and change the offset. Then add this sublayer underneath
layer.addsubview(yourNewView)
I have a question about drawing half of a UIBezierPath. How do I fill left part (left from thumb) with green color and right part (right from thumb) with white color without using CAGradientLayer?
Code I used to create Bezier Path - https://gist.github.com/robertmryan/67484c74297cede3926a3aed2fceedb9
Screenshot of what I want to achieve:
One approach is to add a mask layer to your curved-path shape layer.
When the "thumb" position changes, change the width of the mask to reveal only the "left-side" of the shape layer.
Create a shape layer to use as the mask:
let maskLayer: CALayer = {
let layer = CALayer()
layer.backgroundColor = UIColor.black.cgColor
return layer
}()
In viewDidLoad() set that layer as the mask for the curved-shape layer:
pathLayer.mask = maskLayer
Whenever the "thumb" position is set, update the width of the mask:
func updateMask(at point: CGPoint) -> Void {
var f = view.bounds
f.size.width = point.x
CATransaction.begin()
CATransaction.setDisableActions(true)
maskLayer.frame = f
CATransaction.commit()
}
I posted a modified version of your gist at: https://gist.github.com/DonMag/a2154e70a3c67193a7b19bee41c8fe95
It really has only a few changes... look for comments beginning with // DonMag -
Here is the result (with an imageView behind it to show the transparency):
Edit
After comments, the goal is to have the "right-side" of the track path be white instead of transparent.
Using the same approach, we can add a white shape layer on top of the original shape layer, and mask it to show only the right-hand-side.
Here is an updated gist - https://gist.github.com/DonMag/397dfbe4779e817531ef7a663365b2e7 - showing this result:
I want to make animation, that should look like that:
there a layer on the mainViewLayer, drawn Drop of water with transparent fillColor, I add under it another CAShapeLayer - with blue Color, there layers have the same bounds. and i want to animate its y position, that will imitate decreasing of water level.
fallingWaterLayer = CAShapeLayer()
fallingWaterLayer.frame = x.bounds
fallingWaterLayer.fillColor = UIColor.blue.cgColor
let path = CGPath(rect:fallingWaterLayer.bounds, transform:nil)
fallingWaterLayer.path = path
x.layer.addSublayer(fallingWaterLayer)
mainLayer = DropLayer(x.bounds, shouldFillLayer:false)
x.layer.addSublayer(mainLayer!)
my animation looks like that:
let animation = CABasicAnimation(keyPath: "bounds.origin.y")
animation.toValue = x.bounds.size.width * -1
animation.duration = 5.8
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
animation.fillMode = kCAFillModeBoth
animation.isRemovedOnCompletion = false
fallingWaterLayer.add(animation, forKey: animation.keyPath)
So the question is how can i make top Layer clips the blue rect, to make it look like animation is done inside the Drop of water?
Every CALayer has a mask property, which can be any arbitrary other layer, so that seems like it would be a good solution.
https://developer.apple.com/reference/quartzcore/calayer/1410861-mask
The way the mask property works is that any transparent pixel of the mask will be clipped in the target layer. So you'll need to create a second, solid water drop layer to use as the mask - you can't re-use the same water drop outline, otherwise the water will be clipped to just the border of the water drop, instead of filling the inside.
I'm trying to draw several shapes (rectangle, triangle, circle, ...) in swift and for that, I use uibezierpath but I am not able to draw exactly what I want.
I need to draw for example a rectangle, but the borders of this rectangle need to have different line width.
To do that, I create different path then use the "appendpath" to merge them in one path. So that works, BUT I also need to have a background image in this rectangle.
For that, I create a layer and set it an image. The issue is that, no background image are displayed when I use "appendpath", certainly because it doesn't recognize my drawing as a rectangle.
I hope it is clear enough, but is there a way to draw a shape with a background image, and have different border width ?
Thanks for your help !!
There are two solutions I'd suggest you try:
1) Masking
Create a normal CALayer and set the image as its contents. Then create a CAShapeLayer with the path you like and use it as the first layer's mask.
E.g.:
let imageLayer = CALayer()
imageLayer.contents = UIImage(named: "yourImage")?.CGImage // Your image here
imageLayer.frame = ... // Define a frame
let maskPath = UIBezierPath(...) // Create your path here
let maskLayer = CAShapeLayer()
maskLayer.path = maskPath.CGPath
imageLayer.mask = maskLayer
Don't forget to set the right frames and paths, and you should be able to achieve the effect you wanted.
2) Fill color
Create a CAShapeLayer with the path you like, then use your image as its fillColor.
E.g.:
let path = UIBezierPath(...) // Create your path here
let layer = CAShapeLayer()
layer.path = path.CGPath
let image = UIImage(named: "yourImage") // Your image here
layer.fillColor = UIColor(patternImage: image!).CGColor
You may find this approach easier at first, but controlling the way the image fills your shape is not trivial at all.
I hope this will help.
If you'd like more details, please provide an image or a sketch of what you're trying to achieve and / or the code you've written so far. Thanks!