2014-11-13 4 views
19

Я знаю, что CAGradientLayer не поддерживает радиальный градиент на данный момент и имеет только kCAGradientLayerAxial.Как нарисовать радиальные градиенты в CALayer?

Я хочу кое-что, как показано ниже:

enter image description here

Я посмотрел вокруг этого вопроса и выяснили, что есть способ обойти это. Но объяснения мне не были ясны. Поэтому я хочу знать, могу ли рисовать радиальные градиенты, используя CAGradientLayer, и если да, то как это сделать?

+0

Почему вы не можете использовать 'CGContextDrawRadialGradient'? Вы всегда можете отображать изображение, а затем назначать его содержимому 'CALayer'. Использование 'renderInContext' 'CALayer' также является опцией, но все это приводит к' CGContextDrawRadialGradient'. – Mazyod

+0

@Mazyod У меня есть несколько слоев, добавленных как подуровень к моему UIView, и я рисую bezierPath на этих слоях. Таким образом, все свойства, такие как сплошное заполнение, ширина штриха и т. Д., Связаны со слоем. Поэтому просто хочу поддерживать согласованность кода. – blancos

+0

@Mazyod Также я не получил вашу концепцию рендеринга к изображению, а затем назначил его содержимому CALayer. Не могли бы вы рассказать немного больше. – blancos

ответ

41

Из того, что я понял, вам нужен слой, который рисует градиент, и CGContextDrawRadialGradient отлично работает для этой цели. И чтобы повторить то, что вы сказали, CAGradientLayer не поддерживает радиальные градиенты, и мы ничего не можем с этим поделать, кроме ненужного swizzling, который может быть выполнен с использованием подкласса CALayer.

(Примечание: код градиента рисунок был taken from here Это не то, что этот ответ о..)


viewDidLoad:

GradientLayer *gradientLayer = [GradientLayer new]; 
gradientLayer.frame = self.view.bounds; 

[self.view.layer addSublayer:gradientLayer]; 

CALayer подкласс:

- (instancetype)init 
{ 
    self = [super init]; 
    if (self) { 
     [self setNeedsDisplay]; 
    } 
    return self; 
} 

- (void)drawInContext:(CGContextRef)ctx 
{ 

    size_t gradLocationsNum = 2; 
    CGFloat gradLocations[2] = {0.0f, 1.0f}; 
    CGFloat gradColors[8] = {0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.5f}; 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 
    CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, gradColors, gradLocations, gradLocationsNum); 
    CGColorSpaceRelease(colorSpace); 

    CGPoint gradCenter= CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds)); 
    float gradRadius = MIN(self.bounds.size.width , self.bounds.size.height) ; 

    CGContextDrawRadialGradient (ctx, gradient, gradCenter, 0, gradCenter, gradRadius, kCGGradientDrawsAfterEndLocation); 


    CGGradientRelease(gradient); 
} 

enter image description here

+0

как это можно достичь в SWIFT? – DrPatience

+0

@DrPatience вышеуказанный код напрямую применим к быстрому. Это будет просто «переопределить func drawInContext (ctx: CGContext!) {...' '' –

+0

спасибо @AndyPoes У меня возникают проблемы с этой линией >> «CGContextDrawRadialGradient (ctx, gradient, gradCenter, 0.0, gradCenter, gradRadius, kCGGradientDrawsAfterEndLocation) "и метод экземпляра – DrPatience

14

Вот код Swift3 я использую:

import UIKit 

class RadialGradientLayer: CALayer { 

    required override init() { 
     super.init() 
     needsDisplayOnBoundsChange = true 
    } 

    required init?(coder aDecoder: NSCoder) { 
     super.init(coder: aDecoder) 
    } 

    required override init(layer: Any) { 
     super.init(layer: layer) 
    } 

    public var colors = [UIColor.red.cgColor, UIColor.blue.cgColor] 

    override func draw(in ctx: CGContext) { 
     ctx.saveGState() 

     let colorSpace = CGColorSpaceCreateDeviceRGB() 
     var locations = [CGFloat]() 
     for i in 0...colors.count-1 { 
      locations.append(CGFloat(i)/CGFloat(colors.count)) 
     } 
     let gradient = CGGradient(colorsSpace: colorSpace, colors: colors as CFArray, locations: locations) 
     let center = CGPoint(x: bounds.width/2.0, y: bounds.height/2.0) 
     let radius = min(bounds.width/2.0, bounds.height/2.0) 
     ctx.drawRadialGradient(gradient!, startCenter: center, startRadius: 0.0, endCenter: center, endRadius: radius, options: CGGradientDrawingOptions(rawValue: 0)) 
    } 
} 
+6

Да, это сработало для меня.Замечания пары: - Если вы кодируете проект смешивания и соответствия (Obj-C + Swift), определение массива CGColors вызовет ошибку, поскольку Objective-C не позволяет создавать массив примитивов типы данных. Чтобы преодолеть это, вы можете создать массив UIColors и преобразовать их в значения cgColor в функции 'draw'. - Круг, который был нарисован, имел зубчатые края при добавлении к меньшему подзону. Я исправил это, установив «masksToBounds = true» слоя, а затем добавил добавленный радиус угла, чтобы сделать вид, содержащий слой, кругом, делая ребро гладким. –