Добавить цветовой градиент в круговой индикатор выполнения iOS

У меня возникают трудности с добавлением цветового градиента к круглому индикатору выполнения

введите здесь описание изображения

Моя установка:

  1. Раскадровка: ViewController с пустым представлением, обозначенным как Class CircularProgressBar
  2. Пользовательский класс для CircularProgressBar

Предпринятые шаги:

  1. Я могу загрузить круговой индикатор выполнения
  2. В более ранних попытках я создал слой формы градиента и установил его так, чтобы он был замаскирован границами BarLayer, однако слой формы градиента рисует прямоугольник, начинающийся с центра моего круга, и простирается до нижнего правого угла, поэтому только эта часть BarLayer будет градиент
  3. Когда я переместил начало прямоугольника градиентного слоя, он сместил Barlayer с TrackLayer вместе с ним.

Как я:

Пусть слой градиента покроет весь круговой индикатор выполнения и замаскирует его к BarLayer.

class CircularProgressBar: UIView {

let shapeLayer = CAShapeLayer()
let trackLayer = CAShapeLayer()

override init(frame: CGRect) {
super.init(frame: frame)
    addProgressBar(radius: 5, progress: 0)
}

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
    addProgressBar(radius: 5, progress: 0)
}

func addProgressBar(radius: CGFloat, progress: CGFloat) {

    let lineWidth = radius*0.080

    let circularPath = UIBezierPath(arcCenter: CGPoint(x: bounds.midX, y: bounds.midY), radius: radius, startAngle: 0, endAngle: CGFloat.pi*2, clockwise: true)

    //TrackLayer
    trackLayer.path = circularPath.cgPath
    trackLayer.fillColor = UIColor.lightGray.cgColor
    trackLayer.strokeColor = UIColor.clear.cgColor
    trackLayer.opacity = 0.5
    trackLayer.lineWidth = lineWidth
    trackLayer.lineCap = CAShapeLayerLineCap.round

    //BarLayer
    shapeLayer.path = circularPath.cgPath
    shapeLayer.fillColor = UIColor.clear.cgColor
    shapeLayer.strokeColor = UIColor.systemGreen.cgColor
    shapeLayer.lineWidth = lineWidth
    shapeLayer.strokeEnd = 0
    shapeLayer.lineCap = CAShapeLayerLineCap.round



    //Rotate Shape Layer
    shapeLayer.transform = CATransform3DMakeRotation(-CGFloat.pi/2, 0, 0, 1)

//Shape Shadow
    shapeLayer.shadowColor = UIColor.black.cgColor
    shapeLayer.shadowOffset = CGSize(width: -7, height: 7)
    shapeLayer.shadowRadius = 1
    shapeLayer.shadowOpacity = 0.5

    //Animation
    loadProgress(percentage: progress)

    //LoadLayers
    layer.addSublayer(trackLayer)
    layer.addSublayer(shapeLayer)

}  
func loadProgress(percentage: CGFloat) {

    let basicAnimation = CABasicAnimation(keyPath: "strokeEnd")
    basicAnimation.fromValue = 0
    basicAnimation.duration = 2
    basicAnimation.fillMode = CAMediaTimingFillMode.forwards
    basicAnimation.isRemovedOnCompletion = false
    shapeLayer.strokeEnd = percentage
    shapeLayer.add(basicAnimation, forKey: "basicStroke")

}

ViewController

class HomeViewController: UIViewController {

@IBOutlet weak var containerView: UIView!


var circularProgressBar = CircularProgressBar()
var radius: CGFloat!
var progress: CGFloat!

var answeredCorrect = 0
var totalQuestions = 0


override func viewDidLoad() {
    super.viewDidLoad()

    answeredCorrect = 50
    totalQuestions = 100

    //Configure Progress Bar
    radius = (containerView.frame.height)/2.60
    progress = CGFloat(answeredCorrect) / CGFloat (totalQuestions)
    circularProgressBar.addProgressBar(radius: radius, progress: progress)
    circularProgressBar.center = containerView.center

    //Adding view
    containerView.addSubview(circularProgressBar)


}  
}

person Captain725    schedule 10.05.2020    source источник
comment
чего вы хотите добиться? пожалуйста, покажите окончательное изображение   -  person Jawad Ali    schedule 10.05.2020
comment
чего вы достигли и чего хотите достичь?   -  person Jawad Ali    schedule 10.05.2020


Ответы (1)


Если вы ищете что-то вроде этого

введите здесь описание изображения

Вам нужно обновить код

import UIKit
@IBDesignable
class CircularProgressBar: UIView {

let shapeLayer = CAShapeLayer()
let trackLayer = CAShapeLayer()

override init(frame: CGRect) {
super.init(frame: frame)
   // addProgressBar(radius: 50, progress: 50)
}

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
   // addProgressBar(radius: 50, progress: 50)
}
  override func layoutSubviews() {
    addProgressBar(radius: 50, progress: 50)
  }
func addProgressBar(radius: CGFloat, progress: CGFloat) {

  let lineWidth = CGFloat(10.0)//radius*0.080

    let circularPath = UIBezierPath(arcCenter: CGPoint(x: bounds.midX, y: bounds.midY), radius: radius, startAngle: 0, endAngle: CGFloat.pi*2, clockwise: true)

    //TrackLayer
    trackLayer.path = circularPath.cgPath
    trackLayer.fillColor = UIColor.lightGray.cgColor
    trackLayer.strokeColor = UIColor.clear.cgColor
    trackLayer.lineWidth = lineWidth
    trackLayer.lineCap = CAShapeLayerLineCap.round

    //BarLayer
    shapeLayer.path = circularPath.cgPath
    shapeLayer.fillColor = UIColor.black.cgColor
    shapeLayer.strokeColor = UIColor.systemGreen.cgColor
    shapeLayer.lineWidth = lineWidth*2
    //shapeLayer.strokeEnd = 0
    shapeLayer.lineCap = CAShapeLayerLineCap.round

    //Rotate Shape Layer
   // shapeLayer.transform = CATransform3DMakeRotation(-CGFloat.pi/2, 0, 0, 1)

    //Animation
   // loadProgress(percentage: progress)

    //LoadLayers
   layer.addSublayer(trackLayer)
   self.addGradient()

  // layer.addSublayer(shapeLayer)

}

  private func addGradient() {
    let gradient = CAGradientLayer()
    gradient.colors = [UIColor.red.cgColor,UIColor.purple.cgColor,UIColor.systemPink.cgColor,UIColor.blue.cgColor]
    gradient.frame = bounds
    gradient.mask = shapeLayer
    layer.addSublayer(gradient)
  }
}

И для равномерного градиента вы можете заменить метод addGradient

введите здесь описание изображения

private func addGradient() {
    let gradient = CAGradientLayer()
    gradient.colors = [UIColor.red.cgColor,UIColor.cyan.cgColor,UIColor.brown.cgColor,UIColor.blue.cgColor]
    gradient.frame = bounds
    gradient.locations = [0.2,0.5,0.75,1]
    gradient.startPoint = CGPoint(x: 0.5, y: 0.5)
    gradient.endPoint = CGPoint(x: 0.5, y: 0)
    gradient.type = .conic
    gradient.mask = shapeLayer
    layer.addSublayer(gradient)
  }
person Jawad Ali    schedule 10.05.2020
comment
Эй, джавадАли, еще раз спасибо за ваши ответы. Я добавил изображения индикатора выполнения (градиент будет от темно-зеленого вверху до светло-зеленого внизу), а также некоторый код анимации для его загрузки, как только появится контроллер представления. - person Captain725; 10.05.2020
comment
Нужно ли мне вносить какие-либо изменения в мой код контроллера представления? - person Captain725; 10.05.2020
comment
loadProgress(percentage: progress) обновите этот метод, я спрашиваю - person Jawad Ali; 10.05.2020
comment
Подойдет, добавил код анимации прямо под кодом addSublayers в первом поле кода как отдельную функцию - person Captain725; 10.05.2020
comment
Давайте продолжим обсуждение в чате. - person Jawad Ali; 10.05.2020