How to call function from custom UIView class? - ios

I have UIView in my first view controller. I have set that UIView class to Custom Progress View using following code.
class ProgressView: UIView {
let trackLayer = CAShapeLayer()
let shapeLayer = CAShapeLayer()
static let instance = ProgressView()
override func awakeFromNib() {
super.awakeFromNib()
let center = CGPoint.init(x: frame.width / 2, y: frame.height / 2)
let circularPath = UIBezierPath(arcCenter: center, radius: 30, startAngle: -CGFloat.pi / 2, endAngle: 2 * CGFloat.pi, clockwise: true)
trackLayer.path = circularPath.cgPath
trackLayer.strokeColor = #colorLiteral(red: 0.4745098054, green: 0.8392156959, blue: 0.9764705896, alpha: 1)
trackLayer.lineWidth = 3
trackLayer.fillColor = #colorLiteral(red: 0.5568627715, green: 0.3529411852, blue: 0.9686274529, alpha: 1)
trackLayer.lineCap = kCALineCapRound
self.layer.addSublayer(trackLayer)
shapeLayer.path = circularPath.cgPath
shapeLayer.strokeColor = #colorLiteral(red: 0.8078431487, green: 0.02745098062, blue: 0.3333333433, alpha: 1)
shapeLayer.lineWidth = 3
shapeLayer.fillColor = #colorLiteral(red: 0.3794638515, green: 0.5145698786, blue: 0.9605538249, alpha: 1)
shapeLayer.lineCap = kCALineCapRound
shapeLayer.strokeEnd = 0
self.layer.addSublayer(shapeLayer)
}
}
There is also a function inside that custom UIView class which is for starting animation for filling circle with following code
func startProgress() {
let basicAnimation = CABasicAnimation(keyPath: "strokeEnd")
basicAnimation.toValue = 1
basicAnimation.duration = 60
basicAnimation.fillMode = kCAFillModeForwards
basicAnimation.isRemovedOnCompletion = false
shapeLayer.add(basicAnimation, forKey: "soBasic")
}
I need to call that startProgress function inside my First View controller. In viewDidLoad I have called ProgressView.instance.startProgress() but it is not firing. How can I call start progress function from another class?

In ProgressView you need to create an initialise or you can use default one.
class ProgressView: UIView {
//you can set any additional properties in it.
override init(frame: CGRect) {
super.init(frame: frame)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
How to use
In view controller where you wanna use...
let pgView = ProgressView() //or any other initialise if you have created
.
.
.
pgView.startProgress()

Related

How to draw PieChart, Obtained Marks fill with some colour out of Total Marks without 3rd party library iOS Swift

I want like this
Any code example will be appreciated
Here is a starting point ... created a circular progress view for your help
import UIKit
public class CircularProgressView: UIView {
// First create two layer properties
private lazy var circleLayer : CAShapeLayer = {
let shape = CAShapeLayer()
shape.fillColor = UIColor.clear.cgColor
shape.lineCap = .round
shape.lineWidth = 30.0
shape.strokeColor = #colorLiteral(red: 0.7999292612, green: 0.8000453115, blue: 0.7999040484, alpha: 1)
return shape
}()
private lazy var progressLayer : CAShapeLayer = {
let progress = CAShapeLayer()
progress.fillColor = UIColor.clear.cgColor
// progress.lineCap = .round
progress.lineWidth = 30.0
progress.strokeEnd = 0
progress.strokeColor = #colorLiteral(red: 0.07347138971, green: 0.5590900779, blue: 0.8216868043, alpha: 1)
return progress
}()
override init(frame: CGRect) {
super.init(frame: frame)
createCircularPath()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
createCircularPath()
}
private func createCircularPath() {
updatePath()
layer.addSublayer(circleLayer)
layer.addSublayer(progressLayer)
}
public override func layoutSubviews() {
updatePath()
}
private func updatePath() {
let circularPath = UIBezierPath(arcCenter: CGPoint(x: frame.size.width / 2.0, y: frame.size.height / 2.0), radius: 80, startAngle: -.pi / 2, endAngle: 3 * .pi / 2, clockwise: true)
circleLayer.path = circularPath.cgPath
progressLayer.path = circularPath.cgPath
}
}
public extension CircularProgressView {
func progressAnimation(_ percentage:Float) {
let circularProgressAnimation = CABasicAnimation(keyPath: "strokeEnd")
circularProgressAnimation.duration = 1
circularProgressAnimation.toValue = Float( percentage / 100 )
circularProgressAnimation.fillMode = .forwards
circularProgressAnimation.isRemovedOnCompletion = false
progressLayer.add(circularProgressAnimation, forKey: "progressAnim")
}
}
What you actually want is something custom. This can be built custom or you can use a thridparty library with certain modifications. You a bunch of them on cocoapods but the one i would suggest is
https://github.com/danielgindi/Charts

Adding shadow layer with rounded corners on custom UIButton subclass

I'm trying to apply a shadow and rounded corners on custom UIButton subclass to use in on the storyboard
Here is my code :
import UIKit
class customButton: UIButton {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
setGradientBackground()
setShadowLayer()
}
private func setup() {
clipsToBounds = true
layer.cornerRadius = 8
}
private func setGradientBackground() {
let gradientLayer = CAGradientLayer()
gradientLayer.frame = bounds
gradientLayer.colors = [
UIColor(red: 0.18, green: 0.5, blue: 0.93, alpha: 1).cgColor,
UIColor(red: 0.18, green: 0.61, blue: 0.86, alpha: 1).cgColor
]
gradientLayer.locations = [0,1]
gradientLayer.startPoint = CGPoint(x: 0.25, y: 0.5)
gradientLayer.endPoint = CGPoint(x: 0.75, y: 0.5)
layer.insertSublayer(gradientLayer, at: 0)
}
private func setShadowLayer(){
let subLayer = CALayer()
subLayer.frame = bounds
subLayer.shadowPath = UIBezierPath(roundedRect: bounds, cornerRadius: 8).cgPath
subLayer.shadowColor = UIColor.red.cgColor
subLayer.shadowOpacity = 1
subLayer.shadowRadius = 12
subLayer.shadowOffset = CGSize(width: 0, height: 2)
layer.insertSublayer(subLayer, at: 0)
}
}
When I'm setting the clipsToBounds to true it remove the shadow, so I decided to add a new sublayer func setShadowLayer() and nothing worked so far.
Try also setting the .cornerRadius on the gradient layer:
gradientLayer.endPoint = CGPoint(x: 0.75, y: 0.5)
// add this line
gradientLayer.cornerRadius = 8
layer.insertSublayer(gradientLayer, at: 0)
My result:

swift: Change size of UIView

I use this class to create circular progress:
class ProgressBarView: UIView {
var bgPath: UIBezierPath!
var shapeLayer: CAShapeLayer!
var progressLayer: CAShapeLayer!
var progress: Float = 0 {
willSet(newValue)
{
progressLayer.strokeEnd = CGFloat(newValue)
}
}
override init(frame: CGRect) {
super.init(frame: frame)
bgPath = UIBezierPath()
self.simpleShape()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
bgPath = UIBezierPath()
self.simpleShape()
}
func simpleShape()
{
createCirclePath()
shapeLayer = CAShapeLayer()
shapeLayer.path = bgPath.cgPath
shapeLayer.lineWidth = 2.5
shapeLayer.fillColor = nil
shapeLayer.strokeColor = UIColor.black.cgColor.copy(alpha: 0.2)
progressLayer = CAShapeLayer()
progressLayer.path = bgPath.cgPath
progressLayer.lineCap = kCALineCapRound
progressLayer.lineWidth = 2.5
progressLayer.fillColor = nil
progressLayer.strokeColor = UIColor(red: 0/255, green: 122/255, blue: 255/255, alpha: 1.0).cgColor
progressLayer.strokeEnd = 0.0
self.layer.addSublayer(shapeLayer)
self.layer.addSublayer(progressLayer)
}
private func createCirclePath()
{
let x = self.frame.width/2
let y = self.frame.height/2
let center = CGPoint(x: x, y: y)
print(x,y,center)
bgPath.addArc(withCenter: center, radius: x, startAngle: CGFloat(11), endAngle: CGFloat(17.28), clockwise: true)
bgPath.close()
}
}
And in my ViewController I use this class for my progressView. I want to change size of my progressView for iPhone SE. I trying create width constraint in storyboard and change size of progressView programmatically like:
if self.view.frame.height == 568 {
progressViewWidthConstraint.constant = 100
}
But it doesn't work. How to change size for iPhone SE?
Update
You need to re-layout
progressViewWidthConstraint.constant = 100
self.view.layoutIfNeeded()

create an Arc in swift for Ui collection view

Hi i like to create the following view in ios swift for adding in UIcollection view , how can i achieve this ?
my current code to draw which is returning circle view
#IBInspectable public var fillColor: UIColor = #colorLiteral(red: 0.8078431487, green: 0.02745098062, blue: 0.3333333433, alpha: 1) { didSet { setNeedsLayout() } }
#IBInspectable public var strokeColor: UIColor = #colorLiteral(red: 0.9254902005, green: 0.2352941185, blue: 0.1019607857, alpha: 1) { didSet { setNeedsLayout() } }
#IBInspectable public var lineWidth: CGFloat = 0 { didSet { setNeedsLayout() } }
lazy private var shapeLayer: CAShapeLayer = {
let _shapeLayer = CAShapeLayer()
self.layer.insertSublayer(_shapeLayer, at: 0)
return _shapeLayer
}()
override func layoutSubviews() {
super.layoutSubviews()
let center = CGPoint(x: bounds.midX, y: bounds.midY)
let radius = (min(bounds.size.width, bounds.size.height) - lineWidth) / 2
shapeLayer.path = UIBezierPath(arcCenter: center, radius: radius, startAngle: 0, endAngle: 90, clockwise: true).cgPath
shapeLayer.fillColor = fillColor.cgColor
shapeLayer.strokeColor = strokeColor.cgColor
shapeLayer.lineWidth = lineWidth
}
You can draw the arc in view using BezierPath. Add this arcView in your collection view cell.
Let's see the ArcView :
class ArcView : UIView {
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .white
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func draw(_ rect: CGRect) {
super.draw(rect)
createArc(rect: rect)
}
private func createArc(rect : CGRect) {
let center = CGPoint(x: rect.width/2, y: rect.height/2)
let lineWidth : CGFloat = 50.0
let radius = rect.width / 2 - lineWidth
let startingAngle = CGFloat(-10.0/180) * CGFloat.pi
let endingAngle = CGFloat(-80/180.0) * CGFloat.pi
let bezierPath = UIBezierPath(arcCenter: center, radius: radius, startAngle: startingAngle , endAngle: endingAngle, clockwise: false)
bezierPath.lineWidth = lineWidth
UIColor(red: 249/255.0, green: 179/255.0, blue: 127/255.0, alpha: 1.0).setStroke()
bezierPath.stroke()
}
}
The center of arc is the middle of view.
Drawing the arc from -10 degree to -80 degree in anti-clockwise direction.
Adding the ArcView in ViewController's view Hierarchy (You will add this view in your collectionView Cell)
import UIKit
class ViewController: UIViewController {
private var arcView : ArcView!
override func viewDidLoad() {
super.viewDidLoad()
arcView = ArcView(frame: view.frame)
view.addSubview(arcView)
arcView.setNeedsDisplay()
}
}
Output :
The sample code is here
Try this and set angle as you want
let circlePath = UIBezierPath(arcCenter: CGPoint(x: 100,y: 100), radius: CGFloat(20), startAngle: CGFloat(0), endAngle:CGFloat(Double.pi / 2), clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
//change the fill color
shapeLayer.fillColor = UIColor.clear.cgColor
//you can change the stroke color
shapeLayer.strokeColor = UIColor.red.cgColor
//you can change the line width
shapeLayer.lineWidth = 3.0
view.layer.addSublayer(shapeLayer)

iOS rounding UIView corners with draw enabled

When draw method is commented out inside the below code the view shows up circular, but when it is uncommented out the view shows up as a rectangle again. I could comment out the body of draw to have it just be an empty method, but the view would still show up as a rectangle.
I've tried moving the cornerRadius line to the end of draw, beginning of draw, and end of drawInnerCircle but to no avail. I was wondering if there was still a way to make the view rounded with draw method enabled?
import UIKit
class IconView: UIView {
override init(frame:CGRect) {
super.init(frame : frame)
self.backgroundColor = UIColor(red: 47/255, green: 49/255, blue: 53/255, alpha: 1.0)
self.layer.cornerRadius = self.frame.size.height / 2.0
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override func draw(_ rect: CGRect) {
drawInnerCircle()
}
internal func drawInnerCircle() -> () {
let halfSize:CGFloat = min( self.frame.size.width/2, bounds.size.height/2)
let desiredLineWidth:CGFloat = 1 // your desired value
let circlePath = UIBezierPath(
arcCenter: CGPoint(x:halfSize,y:halfSize),
radius: CGFloat( halfSize - 3 ),
startAngle: CGFloat(0),
endAngle:CGFloat(M_PI * 2),
clockwise: true)
let shapeLayer = CAShapeLayer()
shapeLayer.path = circlePath.cgPath
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = UIColor(red: 96/255, green: 99/255, blue: 105/255, alpha: 1.0).cgColor
shapeLayer.lineWidth = desiredLineWidth
layer.addSublayer(shapeLayer)
}
}
Add the following:
self.layer.masksToBounds = true
below the line:
self.layer.cornerRadius = self.frame.size.height / 2.0
By the way there are some problem described by the above comments.

Resources