I want to hav this kind of animation in my app, a case where an arrow shape such that when clicked it transforms into a mark.
This is what i have at present using the code below
func handleTransform(){
let arrowPath = UIBezierPath()
arrowPath.move(to: CGPoint(x: 50, y: 0))
arrowPath.addLine(to: CGPoint(x: 25, y: 75))
arrowPath.addLine(to: CGPoint(x: 25, y: 75))
arrowPath.addLine(to: CGPoint(x: 25, y: 45))
arrowPath.addLine(to: CGPoint(x: 25, y: 35))
arrowPath.close()
let progressLines = CAShapeLayer()
progressLines.path = arrowPath.cgPath
progressLines.strokeColor = UIColor.black.cgColor
progressLines.fillColor = UIColor.clear.cgColor
progressLines.lineWidth = 10.0
progressLines.lineCap = kCALineCapRound
self.view.layer.addSublayer(progressLines)
let animateStrokeEnd = CABasicAnimation(keyPath: "strokeEnd")
animateStrokeEnd.duration = 3.0
animateStrokeEnd.fromValue = 0.0
animateStrokeEnd.toValue = 1.0
progressLines.add(animateStrokeEnd, forKey: "animate stroke end animation")
}
the flow is illustrated in the images bellow
On click of this image
It transform to this image
I have been able t solve, i did a switch image with animation
Related
The following code effectively animates and scales a view along a BezierPath but I feel like I'm cheating since I'm mixing UIKit and CAKeyframeAnimation (Core Animation) animations.
Is there a better way to scale a view while animating it along the BezierPath?
func animateIt(){
let myView = UIView(frame: CGRect(x: 0, y: 0, width: 50, height: 50))
myView.backgroundColor = .blue
myView.layer.cornerRadius = myView.frame.height / 2
view.addSubview(myView)
let startPoint = CGPoint(x: 250, y: 500)
let apexPoint = CGPoint(x: 100, y: 50)
let endPoint = CGPoint(x: 50, y: 350)
let durationTime = 1.5
let path = UIBezierPath()
path.move(to: startPoint)
path.addQuadCurve(to: endPoint, controlPoint: apexPoint)
let animation = CAKeyframeAnimation(keyPath: "position")
animation.path = path.cgPath
animation.duration = durationTime
myView.layer.add(animation, forKey: "bezier")
myView.center = endPoint
UIView.animate(withDuration: durationTime, animations: {
myView.transform = CGAffineTransform(scaleX: 0.5, y: 0.5);
})
}
I tried using a second CAKeyframeAnimation animation instead of the UIKit animation and used the array of key values but no matter what I do, I cannot get a uniform scale, it scales at the beginning but not at the end.
let scaleAnimation = CAKeyframeAnimation(keyPath: "scale")
scaleAnimation.values = [1.0, 0.9, 0.5,]
myView.layer.add(scaleAnimation, forKey: "scale")
Thanks!
How to make uiview with oval shape at bottom side only with shadow
You need to use UIBezierPath for this. Here is an example (just need to play with the values):
let layer = CAShapeLayer()
layer.fillColor = UIColor.red.cgColor
layer.shadowOffset = CGSize(width: 0, height: 2)
layer.shadowRadius = 5
layer.shadowColor = UIColor.black.cgColor
layer.shadowOpacity = 0.5
layer.shadowRadius = 2
view.layer.addSublayer(layer)
let path = UIBezierPath()
path.move(to: .zero)
path.addLine(to: CGPoint(x: view.frame.maxX, y: 0))
path.addLine(to: CGPoint(x: view.frame.maxX, y: 50))
path.addQuadCurve(to: CGPoint(x: 0, y: 50), controlPoint: CGPoint(x: view.frame.midX, y: 70))
path.close()
layer.path = path.cgPath
and result:
In the following example I'm trying to insert a CATextLayer inside a UIBezierPath and rotate it -45 degrees.
class DiagonalView: UIView {
override func draw(_ rect: CGRect) {
let path = UIBezierPath()
path.move(to: .init(x: rect.maxX, y: rect.midY + (rect.midY / 2.5)))
path.addLine(to: .init(x: rect.midX + (rect.midX / 2.5), y: rect.maxY))
path.addLine(to: .init(x: rect.midX - (rect.midX / 10.5), y: rect.maxY))
path.addLine(to: .init(x: rect.maxX, y: rect.midY - (rect.midY / 10.5)))
let shapeLayer = CAShapeLayer()
shapeLayer.path = path.cgPath
shapeLayer.fillColor = UIColor.black.cgColor
layer.addSublayer(shapeLayer)
let textlayer = CATextLayer.init()
textlayer.string = "iPhone X"
textlayer.fontSize = 12
textlayer.isWrapped = true
textlayer.foregroundColor = UIColor.white.cgColor
textlayer.frame = path.bounds
let degrees = -45.0
let radians = CGFloat(degrees * Double.pi / 180)
textlayer.transform = CATransform3DMakeTranslation(10, 50, 0)
textlayer.transform = CATransform3DMakeRotation(radians, 0.0, 0.5, 1.0)
layer.addSublayer(textlayer)
}
}
let containerView = DiagonalView(frame: CGRect(x: 0.0, y: 0.0, width: 140.0, height: 140.0))
containerView.backgroundColor = .red
PlaygroundPage.current.liveView = containerView
Although its not actually the result that I expected
Result
Expected
Any idea of what mistake I might have done with the code?
Thanks a lot for your time!
How can we fill a shape layer with image in iOS using swift 4 ? I have tried using below. I got an Black background. Here self is a Shapelayer where i am going to set an Image
let image = UIImage(named: "ACVResources.bundle/temp.png")!
let imageLayer = CALayer()
imageLayer.contents = UIImage(named: "image")?.cgImage // Assign your image
imageLayer.frame = self.frame
imageLayer.mask = self
self.masksToBounds = true
self.setNeedsDisplay()
First, you have to add CALayer(imageLayer) that fill your view after that you need to set that your view.layer mask your shapeLayer.
I give you an example:
let customView = UIView(frame: CGRect(x: 0, y: 0, width: 300, height: 500))
customView.backgroundColor = .red
view.addSubview(customView)
let imageLayer = CALayer()
let image = UIImage(named: "pxl.jpeg")
imageLayer.contents = image?.cgImage
imageLayer.frame = customView.frame
customView.layer.addSublayer(imageLayer)
let shape = CAShapeLayer()
let path = UIBezierPath()
path.move(to: CGPoint(x: customView.frame.size.width / 2, y: 50))
path.addLine(to: CGPoint(x: customView.frame.size.width, y: customView.frame.size.height / 2))
path.addLine(to: CGPoint(x: 0, y: customView.frame.size.height / 2))
path.close()
shape.path = path.cgPath
customView.layer.mask = shape
screenshot of that code
All of the explanations I've found seem to say the same thing. I can't figure out why this isn't working.
var linePath = UIBezierPath()
linePath.move(to: CGPoint(x: 50, y: 50))
linePath.addLine(to: CGPoint(x: 100, y: 100))
var pattern : [CGFloat] = [10.0, 10.0]
linePath.setLineDash(pattern, count: pattern.count, phase: 0)
linePath.lineWidth = 10
linePath.lineCapStyle = .round
let shape = SKShapeNode()
shape.path = linePath.cgPath
shape.strokeColor = UIColor.white
self.addChild(shape)
This code successfully draws a line but shape does not inherit the dashed properties of linePath, including even the width. Any ideas?
let linePath = UIBezierPath()
linePath.move(to: CGPoint(x: 50, y: 50))
linePath.addLine(to: CGPoint(x: 100, y: 100))
var pattern: [CGFloat] = [10.0, 10.0]
let dashed = CGPathCreateCopyByDashingPath (linePath.CGPath, nil, 0, pattern, 2)
var shape = SKShapeNode(path: dashed)
shape.strokeColor = UIColor.white
self.addChild(shape)
NOTE: In Swift 3 CGPathCreateCopyByDashingPath has been replaced by path.copy(dashingWithPhase:lengths:)
e.g.
let dashed = SKShapeNode(path: linePath.cgPath.copy(dashingWithPhase: 2, lengths: pattern))