#ios #swift #xcode
#iOS #swift #xcode
Вопрос:
У меня проблема с добавлением градиента в CAShapeLayer. Я создал слой circle и хочу добавить к нему градиент. Итак, я создал CAGradientLayer и установил для него рамки в качестве границ слоя и маску в качестве слоя, но она не отображается. Что я могу сделать?
private func setupCircle() -> CAShapeLayer {
let circlePath = UIBezierPath(arcCenter: CGPoint(x: progressView.frame.size.width / 2.0, y: progressView.frame.size.height / 2.0), radius: (progressView.frame.size.width - 10)/2, startAngle: 0.0, endAngle: CGFloat(M_PI * 2.0), clockwise: true)
let circleLayer = CAShapeLayer()
circleLayer.path = circlePath.CGPath
circleLayer.fillColor = nil
circleLayer.strokeColor = UIColor.yellowColor().CGColor
circleLayer.backgroundColor = UIColor.yellowColor().CGColor
circleLayer.lineWidth = configurator.lineWidth
circleLayer.strokeEnd = 1.0
return circleLayer
}
private func setupGradient() -> CAGradientLayer {
let gradient = CAGradientLayer()
gradient.colors = [UIColor.clearColor().CGColor, UIColor.yellowColor().CGColor, UIColor.greenColor().CGColor]
gradient.locations = [0.0, 0.25, 1.0]
gradient.startPoint = CGPointMake(0, 0)
gradient.endPoint = CGPointMake(1, 1)
return gradient
}
let circle = setupCircle()
let gradient = setupGradient()
gradient.frame = circle.bounds
gradient.mask = circle
progressView.layer.addSublayer(circle)
progressView.layer.insertSublayer(gradient, atIndex: 0)
Редактировать:
Я изменил метод setupCircle на:
private func setupCircle() -> CAShapeLayer {
let circleLayer = CAShapeLayer()
circleLayer.frame = progressView.bounds.insetBy(dx: 5, dy: 5)
circleLayer.path = UIBezierPath(ovalInRect: CGRectMake(progressView.center.x, progressView.center.y, progressView.bounds.size.width, progressView.bounds.size.height)).CGPath
circleLayer.fillColor = nil
circleLayer.strokeColor = UIColor.yellowColor().CGColor
circleLayer.backgroundColor = UIColor.yellowColor().CGColor
circleLayer.lineWidth = configurator.lineWidth
circleLayer.strokeEnd = 1.0
return circleLayer
}
И вот эффект, я сделал это правильно?:
ПРАВКА 2: я изменил circleLayer.path = UIBezierPath(ovalInRect: CGRectMake(progressView.center.x, progressView.center.y, progressView.bounds.size.width, progressView.bounds.size.height)).CGPath
на circleLayer.path = UIBezierPath(ovalInRect: circleLayer.bounds).CGPath
, и это лучше, но все еще не то, что я хочу:
Комментарии:
1. Какова область действия этой строки
let circle = setupCircle()
и кода ниже? это переменная экземпляра или локальная переменная вviewDidLoad
или что-то еще?2. Это в методе установки, который вызывается в viewDidLoad
3. Проверьте обновленный ответ, он должен устранить ваши проблемы.
Ответ №1:
Это нормально, что вы создаете слои и добавляете их в иерархию слоев в viewDidLoad
, но вам не следует использовать там какую-либо фреймовую логику, поскольку макет в этот момент не обновляется. Попробуйте переместить весь код, который выполняет какие-либо вычисления фрейма в viewDidLayoutSubviews
.
Это также следует делать при каждом обновлении макета, поэтому перемещайте его с setupCircle
на viewDidLayoutSubviews
:
let circlePath = UIBezierPath(...)
circleLayer.path = circlePath.cgPath
Редактировать:
Также я не вижу, где вы устанавливаете circleLayer
рамку? Недостаточно задать его путь. Если у вас есть CGRect.zero rect для маски, она полностью скроет родительский слой.
Я бы рекомендовал заменить это:
let circlePath = UIBezierPath(arcCenter: CGPoint(x: progressView.frame.size.width / 2.0, y: progressView.frame.size.height / 2.0), radius: (progressView.frame.size.width - 10)/2, startAngle: 0.0, endAngle: CGFloat(M_PI * 2.0), clockwise: true)
с помощью этого:
circleLayer.bounds = progressView.frame.insetBy(dx: 5, dy: 5)
circleLayer.path = UIBezierPath(ovalIn: circleLayer.bounds).cgPath
Таким образом, у вас будут заданы и рамка, и контур. Также будьте осторожны с системой координат. Я не уверен насчет того, где находится progressView
в вашей иерархии представлений, возможно, вам это понадобится bounds
вместо этого.
Правка 2: Также вам следует удалить там несколько строк кода.
- Это делает ваш слой circle полностью непрозрачным, делает саму фигуру невидимой.
circleLayer.backgroundColor = UIColor.yellowColor().CGColor
- Вам не следует добавлять circle в качестве подслоя, поскольку вы собираетесь использовать его в качестве маски:
progressView.layer.addSublayer(circle)
Комментарии:
1. Он по-прежнему не отображается
2. Только что обнаружил еще одну ошибку. Убедитесь, что вы установили рамку для
mask
слоя3. Спасибо, я не устанавливал frame для layer. Как я могу установить фрейм на основе path?
4. @Woodgun11 Вам лучше сначала рассчитать фрейм, а затем создать
path
на основе этого фрейма.5. Попробуйте
UIBezierPath(ovalIn: circleLayer.bounds).cgPath
вместо этого. Вам это больше не нужноprogressView.frame
.