Scale down UIView and it's subview simultaneously in swift 5? - ios

I have created UIView and it has one subview and it's containing shape object which are creating using UIBezierPath, and UIView has fixed height and width (image 1). When i click the blue color button, it should be scale down to another fixed width and height. I have applied CGAffineTransform to subview and, i guess it is scale down properly, but since topAnchor and leftAchor has constant values, after scale down it is not displaying properly (image 2).I will attach my source code here and screenshots, please, analyze this and can someone suggest better approach for how to do this ? and highly appreciate ur feedback and comments.
code:
import UIKit
class ViewController: UIViewController {
var screenView: UIView!
var button: UIButton!
let widthOfScaleDownView: CGFloat = 200
let heightOfScaleDownView: CGFloat = 300
override func viewDidLoad() {
screenView = UIView(frame: .zero)
screenView.translatesAutoresizingMaskIntoConstraints = false
screenView.backgroundColor = UIColor.red
self.view.addSubview(screenView)
NSLayoutConstraint.activate([
screenView.heightAnchor.constraint(equalToConstant: 800),
screenView.widthAnchor.constraint(equalToConstant: 600),
screenView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor, constant: 0),
screenView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor, constant: 0)
])
button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.backgroundColor = UIColor.blue
self.view.addSubview(button)
NSLayoutConstraint.activate([
button.heightAnchor.constraint(equalToConstant: 50),
button.widthAnchor.constraint(equalToConstant: 100),
button.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 950),
button.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 350)
])
button.setTitle("click", for: .normal)
button.setTitleColor(UIColor.white, for: .normal)
button.addTarget(self, action: #selector(scaleDownView(_:)), for: .touchUpInside)
let shapeView = UIView(frame: .zero)
shapeView.translatesAutoresizingMaskIntoConstraints = false
let rect = CGRect(x: 0, y: 0, width: 300, height: 300)
let shape = UIBezierPath(roundedRect: rect, cornerRadius: 50)
let layer = CAShapeLayer()
layer.path = shape.cgPath
layer.lineWidth = 2
shapeView.layer.addSublayer(layer)
screenView.addSubview(shapeView)
NSLayoutConstraint.activate([
shapeView.topAnchor.constraint(equalTo: screenView.topAnchor, constant: 250),
shapeView.leftAnchor.constraint(equalTo: screenView.leftAnchor, constant: 150)
])
}
#IBAction func scaleDownView(_ sender: UIButton) {
let widthScale = widthOfScaleDownView/screenView.frame.width
let heightScale = heightOfScaleDownView/screenView.frame.height
screenView.subviews.forEach{ view in
view.transform = CGAffineTransform(scaleX: widthScale, y: heightScale)
}
NSLayoutConstraint.activate([
screenView.heightAnchor.constraint(equalToConstant: heightOfScaleDownView),
screenView.widthAnchor.constraint(equalToConstant: widthOfScaleDownView),
screenView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor, constant: 0),
screenView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor, constant: 0)
])
}
}

Couple things...
1 - When you use CGAffineTransform to change a view, it will automatically affect the view's subviews. So no need for a loop.
2 - Transforms are cumulative, so when "going back" to the original scale, use .identity instead of another scale transform.
3 - You cannot set a constraint multiple times. So if you do:
screenView.heightAnchor.constraint(equalToConstant: 800)
and then you also do:
screenView.heightAnchor.constraint(equalToConstant: heightOfScaleDownView)
you will get auto-layout conflicts... the view cannot be both 800-pts tall and
300-pts tall at the same time.
Take a look at the changes I made to your code. I also added a 1-second animation to the scale transform so you can see what it's doing:
class ViewController: UIViewController {
var screenView: UIView!
var button: UIButton!
let widthOfScaleDownView: CGFloat = 200
let heightOfScaleDownView: CGFloat = 300
override func viewDidLoad() {
screenView = UIView(frame: .zero)
screenView.translatesAutoresizingMaskIntoConstraints = false
screenView.backgroundColor = UIColor.red
self.view.addSubview(screenView)
// constrain screenView
// width: 800 height: 600
// centered X and Y
NSLayoutConstraint.activate([
screenView.heightAnchor.constraint(equalToConstant: 800),
screenView.widthAnchor.constraint(equalToConstant: 600),
screenView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor, constant: 0),
screenView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor, constant: 0)
])
button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.backgroundColor = UIColor.blue
self.view.addSubview(button)
NSLayoutConstraint.activate([
button.heightAnchor.constraint(equalToConstant: 50),
button.widthAnchor.constraint(equalToConstant: 100),
button.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 950),
button.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 350)
])
button.setTitle("click", for: .normal)
button.setTitleColor(UIColor.white, for: .normal)
button.addTarget(self, action: #selector(scaleDownView(_:)), for: .touchUpInside)
let shapeView = UIView(frame: .zero)
shapeView.translatesAutoresizingMaskIntoConstraints = false
let rect = CGRect(x: 0, y: 0, width: 300, height: 300)
let shape = UIBezierPath(roundedRect: rect, cornerRadius: 50)
let layer = CAShapeLayer()
layer.path = shape.cgPath
layer.lineWidth = 2
shapeView.layer.addSublayer(layer)
screenView.addSubview(shapeView)
// constrain shapeView
// width: 300 height: 300
// centered X and Y in screenView
NSLayoutConstraint.activate([
shapeView.widthAnchor.constraint(equalToConstant: 300.0),
shapeView.heightAnchor.constraint(equalToConstant: 300.0),
shapeView.centerXAnchor.constraint(equalTo: screenView.centerXAnchor),
shapeView.centerYAnchor.constraint(equalTo: screenView.centerYAnchor),
])
}
#IBAction func scaleDownView(_ sender: UIButton) {
let widthScale = widthOfScaleDownView/screenView.frame.width
let heightScale = heightOfScaleDownView/screenView.frame.height
UIView.animate(withDuration: 1.0) {
// if we have already been scaled down
if widthScale == 1 {
// animate the scale transform back to original (don't add another transform)
self.screenView.transform = .identity
} else {
// animate the scale-down transform
self.screenView.transform = CGAffineTransform(scaleX: widthScale, y: heightScale)
}
}
// do NOT change screenView constraints!
}
}

Related

SF Symbols not loading into UIImageView

I am creating an app for tracking health information, and I would like to use the two arrow images from SF Symbols. Unfortunately, no matter what I try, these symbols will not show up.
I have already tested the code with an image from the Assets folder, which seems to work with no problem in the UIImageViews I have created. It is only when I attempt to use UIImage(systemName: ) that I am having problems.
self.calendarView = UIView(frame: CGRect(x: 0, y: self.getCurrentY(), width: UIScreen.main.bounds.width, height: 60))
self.calendarView?.backgroundColor = .white
self.calendarView?.layer.borderColor = UIColor.black.cgColor
self.calendarView?.layer.borderWidth = 1
self.currentDate = UILabel(frame: CGRect(x: self.calendarView!.bounds.width / 4, y: self.calendarView!.bounds.height / 2 - 20, width: self.calendarView!.bounds.width / 2, height: 40))
self.currentDate!.text = "5/6/20"
self.currentDate!.textColor = .black
self.currentDate!.layer.borderColor = UIColor.black.cgColor
self.currentDate?.layer.borderWidth = 1
self.currentDate?.textAlignment = .center
self.calendarView?.addSubview(currentDate!)
//let testImage = UIImage(named: "logotest.jpg")!
let image1 = UIImage(systemName: "arrow.left")!.withTintColor(.blue)
let image2 = UIImage(systemName: "arrow.right")!.withTintColor(.blue)
self.leftArrow = UIImageView(image: image1)
self.rightArrow = UIImageView(image: image2)
self.leftArrow?.frame = CGRect(x: 10, y: 10, width: 40, height: 40)
self.rightArrow?.frame = CGRect(x: UIScreen.main.bounds.width - 50, y: 10, width: 40, height: 40)
self.leftArrow?.layer.borderWidth = 1
self.rightArrow?.layer.borderWidth = 1
self.calendarView!.addSubview(self.leftArrow!)
self.calendarView!.addSubview(self.rightArrow!)
self.contentView.addSubview(self.calendarView!)
What seems even stranger is that when I enter a breakpoint, the images actually show! I've attached a picture of this as well. Any help I can get with this is appreciated. Thanks!
Give your imageViews tint color will resolve the issue
leftArrow.tintColor = .blue
leftArrow.tintColor = .blue
1) You should be using constraints / auto-layout instead of explicit frames.
2) You should use if let and guard let to avoid all those ! and ?
Try it like this:
class ViewController: UIViewController {
var leftArrow: UIImageView!
var rightArrow: UIImageView!
var calendarView: UIView!
var currentDate: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
//self.calendarView = UIView(frame: CGRect(x: 0, y: self.getCurrentY(), width: UIScreen.main.bounds.width, height: 60))
self.calendarView = UIView()
self.calendarView.backgroundColor = .white
self.calendarView.layer.borderColor = UIColor.black.cgColor
self.calendarView.layer.borderWidth = 1
//self.currentDate = UILabel(frame: CGRect(x: self.calendarView!.bounds.width / 4, y: self.calendarView!.bounds.height / 2 - 20, width: self.calendarView!.bounds.width / 2, height: 40))
self.currentDate = UILabel()
self.currentDate.text = "5/6/20"
self.currentDate.textColor = .black
self.currentDate.layer.borderColor = UIColor.black.cgColor
self.currentDate.layer.borderWidth = 1
self.currentDate.textAlignment = .center
//let testImage = UIImage(named: "logotest.jpg")!
guard let imgLeft = UIImage(systemName: "arrow.left"),
let imgRight = UIImage(systemName: "arrow.right") else {
fatalError("Could not create arrow images!")
}
let image1 = imgLeft.withTintColor(.blue)
let image2 = imgRight.withTintColor(.blue)
self.leftArrow = UIImageView(image: image1)
self.rightArrow = UIImageView(image: image2)
//self.leftArrow.frame = CGRect(x: 10, y: 10, width: 40, height: 40)
//self.rightArrow.frame = CGRect(x: UIScreen.main.bounds.width - 50, y: 10, width: 40, height: 40)
self.leftArrow.layer.borderWidth = 1
self.rightArrow.layer.borderWidth = 1
self.calendarView.addSubview(currentDate)
self.calendarView.addSubview(self.leftArrow)
self.calendarView.addSubview(self.rightArrow)
//self.contentView.addSubview(self.calendarView)
self.view.addSubview(self.calendarView)
[calendarView, currentDate, leftArrow, rightArrow].forEach {
$0?.translatesAutoresizingMaskIntoConstraints = false
}
// respect safe area
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
// calendarView to view (safe area) Top / Leading / Trailing
// Height: 60
calendarView.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
calendarView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
calendarView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
calendarView.heightAnchor.constraint(equalToConstant: 60.0),
// currentDate label to calendarView centerX & centerY
// Width: 1/2 of calendarView width
// Height: 40
currentDate.centerXAnchor.constraint(equalTo: calendarView.centerXAnchor),
currentDate.centerYAnchor.constraint(equalTo: calendarView.centerYAnchor),
currentDate.heightAnchor.constraint(equalToConstant: 40.0),
currentDate.widthAnchor.constraint(equalTo: calendarView.widthAnchor, multiplier: 0.5),
// leftArrow to calendarView Leading: 10 Width: 40 Height: 40 centerY
leftArrow.leadingAnchor.constraint(equalTo: calendarView.leadingAnchor, constant: 10.0),
leftArrow.widthAnchor.constraint(equalToConstant: 40.0),
leftArrow.heightAnchor.constraint(equalToConstant: 40.0),
leftArrow.centerYAnchor.constraint(equalTo: calendarView.centerYAnchor),
// rightArrow to calendarView Trailing: -10 Width: 40 Height: 40 centerY
rightArrow.trailingAnchor.constraint(equalTo: calendarView.trailingAnchor, constant: -10.0),
rightArrow.widthAnchor.constraint(equalToConstant: 40.0),
rightArrow.heightAnchor.constraint(equalToConstant: 40.0),
rightArrow.centerYAnchor.constraint(equalTo: calendarView.centerYAnchor),
])
}
}
Output:
and, with auto-layout and constraints, it auto-sizes when needed - such as on device rotation:

Swift - scale background while retaining top anchor

How can I scale a UIImageView while retaining the top anchor?
I tried:
UIView.animate(withDuration: 0.3, animations: {
self.backGroundImage.contentMode = .scaleToFill
self.backGroundImage.transform = CGAffineTransform(scaleX: 3, y: 3)
self.backGroundImage.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
})
That scales the image but the anchor point is the middle of the image. It seems like setting the topAnchor doesn't do anything. Is there a way to set some sort of "scaleAnchor" or some other solution?
In the end I would like to achieve this:
Update
This is how I constrain the view:
NSLayoutConstraint.activate([
// constrain background image
backGroundImage.topAnchor.constraint(equalTo: view.topAnchor),
backGroundImage.bottomAnchor.constraint(equalTo: view.bottomAnchor),
backGroundImage.leadingAnchor.constraint(equalTo: view.leadingAnchor),
backGroundImage.trailingAnchor.constraint(equalTo: view.trailingAnchor), )]
This works for me in Swift 5.1:
public extension UIView {
func applyTransform(withScale scale: CGFloat, anchorPoint: CGPoint) {
let xPadding = (scale - 1) * (anchorPoint.x - 0.5) * bounds.width
let yPadding = (scale - 1) * (anchorPoint.y - 0.5) * bounds.height
transform = CGAffineTransform(scaleX: scale, y: scale).translatedBy(x: xPadding, y: yPadding)
}
}
Example:
yourView.applyTransform(withScale: 3, anchorPoint: CGPoint(x: 0.5, y: 0))
The transform matrix is applied after the frame has been calculated from the constraints. If you want to scale things up consistently I suggest just setting a multiple on the height and width constraints instead. Alternatively you can move the anchor point by using CALayers.anchorPoint and then apply you transform so that it scales from the top middle instead of the center (which is the default).
EDIT -- example:
import PlaygroundSupport
class V: UIViewController {
let square = UIView()
override func viewDidLoad() {
super.viewDidLoad()
square.translatesAutoresizingMaskIntoConstraints = false
square.backgroundColor = .red
view.addSubview(square)
NSLayoutConstraint.activate([
square.centerXAnchor.constraint(equalTo: view.centerXAnchor),
square.centerYAnchor.constraint(equalTo: view.centerYAnchor),
square.widthAnchor.constraint(equalToConstant: 100),
square.heightAnchor.constraint(equalToConstant: 100),
])
square.layer.anchorPoint = .init(x: 0.5, y: 0)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
UIView.animate(withDuration: 10) {
self.square.transform = .init(scaleX: 3, y: 3)
}
}
}
PlaygroundPage.current.liveView = V()

Gradient of UIButton is not showing

I’m trying to put a gradient on a button, but it is not showing up. All the other button parts are working and displaying perfectly!
Function that creates the button
private func createButtonMenu(buttonTitle: String, buttonIcon: UIImage, colorOne: UIColor, colorTwo: UIColor) -> UIButton{
let button = UIButton()
button.setTitle(buttonTitle, for: .normal)
button.translatesAutoresizingMaskIntoConstraints = false
button.contentHorizontalAlignment = .leading
button.contentVerticalAlignment = .bottom
button.contentEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 10, right: 0)
button.layer.cornerRadius = 30
button.layer.masksToBounds = true
let icon = UIImageView(image: buttonIcon)
icon.translatesAutoresizingMaskIntoConstraints = false
button.addSubview(icon)
button.heightAnchor.constraint(equalToConstant: 100).isActive = true
icon.topAnchor.constraint(equalTo: button.topAnchor, constant: 10).isActive = true
icon.leadingAnchor.constraint(equalTo: button.leadingAnchor, constant: 10).isActive = true
let gradientLayer = CAGradientLayer()
gradientLayer.frame = button.bounds
gradientLayer.colors = [UIColor.red, UIColor.blue]
gradientLayer.locations = [0.0, 1.0]
gradientLayer.startPoint = CGPoint(x: 0.0, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 1.0, y: 0.5)
button.layer.insertSublayer(gradientLayer, at: 0)
//button.backgroundColor = .red
icon.widthAnchor.constraint(equalToConstant: 30).isActive = true
icon.heightAnchor.constraint(equalToConstant: 30).isActive = true
return button
}
Function that inserts the button in view
private func configuringButtons(){
//Creating buttons
let userButtonMenu: UIButton = createButtonMenu(buttonTitle: "009", buttonIcon: #imageLiteral(resourceName: "woman"), colorOne: .red, colorTwo: .blue)
view.addSubview(userButtonMenu)
}
Colours in a gradient layer must be of type CGColor, not UIColor.
gradientLayer.colors = [UIColor.red.cgColor, UIColor.blue.cgColor]

Problem when inserting a sublayer below an existing layer in Swift?

I'm trying to add a sublayer behind an existing layer in Swift, but the sublayer is still coming up in front of the existing layer - I must have a problem in my code;
import UIKit
class ViewController: UIViewController {
let mainView = UIView()
let screenWidth = UIScreen.main.bounds.width
let screenHeight = UIScreen.main.bounds.height
let focusBG = UIView()
override func viewDidLoad() {
super.viewDidLoad()
mainView.backgroundColor = UIColor.gray
view.addSubview(mainView)
mainView.translatesAutoresizingMaskIntoConstraints = false
mainView.widthAnchor.constraint(equalToConstant: 325).isActive = true
mainView.heightAnchor.constraint(equalToConstant: ((325 / 9) * 16)).isActive = true
mainView.topAnchor.constraint(equalTo: view.topAnchor, constant: 100).isActive = true
mainView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
let tapView = UIView(frame: CGRect(x: 50, y: 0, width: 150, height: 200))
tapView.backgroundColor = UIColor.red
mainView.addSubview(tapView)
focusBG.frame = CGRect(x: 0, y: 0, width: screenWidth, height: screenHeight)
focusBG.backgroundColor = UIColor(hue: 0.0, saturation: 0.0, brightness: 0.0, alpha: 0.4)
self.view.layer.insertSublayer(focusBG.layer, below: tapView.layer)
}
}
Ideally the red box would be in front of the greyed out layer - but this is what i am getting;
Thanks!
Update: Working Code
self.mainView.insertSubview(focusBG, belowSubview: tapView)
focusBG.translatesAutoresizingMaskIntoConstraints = false
focusBG.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
focusBG.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
focusBG.widthAnchor.constraint(equalToConstant: screenWidth).isActive = true
focusBG.heightAnchor.constraint(equalToConstant: screenHeight).isActive = true
You can try
self.mainView.insertSubview(focusBG, belowSubiew: tapView)
Or
self.mainView.layer.insertSublayer(focusBG.layer, below: tapView.layer) // not tested
Try using insertSublayer, method works for me.
self.mainView.layer.insertSublayer(your_Layer, at: 1) // 1 is the position of the layer you want to add to the mainView.
Thanks and let me know if this works for you. Dont Forget to upvote if it does ;)

Circle UIView resize with animation keeping Circle shape

I have a UIView which I am making the background a circular shape with:
self.colourView.layer.cornerRadius = 350
self.colourView.clipsToBounds = true
With the view being a 700 by 700 square.
I am then trying to change the size of this view using:
UIView.animate(withDuration: zoomLength,
delay: 0,
options: .curveEaseIn,
animations: {
self.colorViewWidth.constant = 100
self.colorViewHeight.constant = 100
self.colourView.layer.cornerRadius = 50
self.colourView.clipsToBounds = true
self.view.layoutIfNeeded()
},
completion: { finished in
})
})
The problem with this is the corner radius of the view switch to 50 instantly. So that as the view shrinks in size it doesn't look like a circle shrinking but a square with rounded corners until it reaches the 100 by 100 size.
How can I take a view that circule in shape and shrink it down while maintaining the circlare shape during the animation.
You could always animate the corner radius as well with a CABasicAnimation along side the UIView animations. See example below.
import UIKit
class ViewController: UIViewController {
//cause 'merica
var colorView = UIView()
var button = UIButton()
var colorViewWidth : NSLayoutConstraint!
var colorViewHeight : NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
colorView.frame = CGRect(x: 0, y: 0, width: 750, height: 750)
colorView.center = self.view.center
colorView.backgroundColor = .blue
colorView.layer.cornerRadius = 350
colorView.clipsToBounds = true
colorView.layer.allowsEdgeAntialiasing = true
colorView.translatesAutoresizingMaskIntoConstraints = false
//set up constraints
colorViewWidth = NSLayoutConstraint(item: colorView, attribute: .width, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 750)
colorViewWidth.isActive = true
colorViewHeight = NSLayoutConstraint(item: colorView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 750)
colorViewHeight.isActive = true
self.view.addSubview(colorView)
colorView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
colorView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
//button for action
button = UIButton(frame: CGRect(x: 0, y: 0, width: self.view.bounds.width - 20, height: 50))
button.center = self.view.center
button.center.y = self.view.bounds.height - 70
button.addTarget(self, action: #selector(ViewController.pressed(sender:)), for: .touchUpInside)
button.setTitle("Animate", for: .normal)
button.setTitleColor(.blue, for: .normal)
self.view.addSubview(button)
}
func pressed(sender:UIButton) {
self.colorViewWidth.constant = 100
self.colorViewHeight.constant = 100
UIView.animate(withDuration: 1.0,
delay: 0,
options: .curveEaseIn,
animations: {
self.view.layoutIfNeeded()
},
completion: { finished in
})
//animate cornerRadius and update model
let animation = CABasicAnimation(keyPath: "cornerRadius")
animation.duration = 1.0
//super important must match
animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn)
animation.fromValue = colorView.layer.cornerRadius
animation.toValue = 50
colorView.layer.add(animation, forKey: nil)
//update model important
colorView.layer.cornerRadius = 50
}
}
Result:
Try to put your image inside a viewDidLayoutSubviews()
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
colourView.layer.cornerRadius = colourView.frame.size.width/2
colourView.layer.masksToBounds = true
colourView.layer.borderWidth = 3.0
colourView.layer.borderColor = UIColor(red: 142.0/255.5, green: 142.0/255.5, blue: 142.0/255.5, alpha: 1.0).cgColor
}
let me know how it goes
Cheers
Regarding animation you need to create the CAShapeLayer object and then set the cgpath of the layer object.
let circleLayer = CAShapeLayer()
let radius = view.bounds.width * 0.5
//Value of startAngle and endAngle should be in the radian.
let path = UIBezierPath(arcCenter: center, radius: radius, startAngle: startAngle, endAngle: endAngle, clockwise: true)
circleLayer.path = path.cgPath
The above will draw the circle for you. After that you can apply the animation on layer object.
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = fromValue//you can update the value here by default it will be 0
animation.toValue = toValue //you can update the value here by default it will be 1
animation.duration = CFTimeInterval(remainingTime)
circleLayer
circleLayer.removeAnimation(forKey: "stroke")
circleLayer.add(animation, forKey: "stroke")

Resources