2009-08-20 2 views
22

Я знаю, как нарисовать простую строку:Как нарисовать линию градиента (затухание в/из) с помощью Core Graphics/iPhone?

CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0); 
CGContextMoveToPoint(context, x, y); 
CGContextAddLineToPoint(context, x2, y2); 
CGContextStrokePath(context); 

И я знаю, как сделать градиент прямоугольник, i.g .:

CGColorSpaceRef myColorspace=CGColorSpaceCreateDeviceRGB(); 
size_t num_locations = 2; 
CGFloat locations[2] = { 1.0, 0.0 }; 
CGFloat components[8] = { 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0 }; 

CGGradientRef myGradient = CGGradientCreateWithColorComponents(myColorspace, components, locations, num_locations); 

CGPoint myStartPoint, myEndPoint; 
myStartPoint.x = 0.0; 
myStartPoint.y = 0.0; 
myEndPoint.x = 0.0; 
myEndPoint.y = 10.0; 
CGContextDrawLinearGradient (context, myGradient, myStartPoint, myEndPoint, 0); 

Но как я мог нарисовать линию с градиентом, i.g. затухание от черного до белого (и, возможно, исчезновение на черном с другой стороны)?

+1

Быстрая заметка - выбранный здесь ответ неверен. ** Можно пропустить произвольные пути с градиентом **, как показывает [этот ответ] (http://stackoverflow.com/a/25034854/2547229). – Benjohn

ответ

20

После нескольких попыток я теперь уверен, что градиенты не влияют на штрихи, поэтому я думаю, что невозможно рисовать градиентные линии с помощью CGContextStrokePath(). Для горизонтальных и вертикальных линий вместо этого нужно использовать CGContextAddRect(), к счастью, это то, что мне нужно. Я заменил

CGContextMoveToPoint(context, x, y); 
CGContextAddLineToPoint(context, x2, y2); 
CGContextStrokePath(context); 

с

CGContextSaveGState(context); 
CGContextAddRect(context, CGRectMake(x, y, width, height)); 
CGContextClip(context); 
CGContextDrawLinearGradient (context, gradient, startPoint, endPoint, 0); 
CGContextRestoreGState(context); 

и все работает отлично. Спасибо Брэду Ларсону за главный намек.

+0

Я нашел то же самое. Похоже, что градиенты требуют, чтобы путь клика (или прямоугольник) сначала применялся к графическому контексту. Возможно, это потому, что градиенты отображаются в окружении, а не на границе пути (или прямоугольника)? – Dalmazio

+0

Это не может сделать отстойную линию? – AntiMoron

8

Вы можете использовать слои Core Animation. Вы можете использовать CAShaperLayer для своей линии, установив свойство его пути, а затем вы можете использовать CAGradientLayer в качестве маски слоя для слоя вашей формы, что приведет к исчезновению линии.

Замените вызовы CGContext ... с вызовами вызовов CGPath ..., чтобы создать линию. Задайте поле пути на слое, используя этот путь. Затем в градиентном слое, определите цвета, которые вы хотите использовать (возможно, от черного к белому), а затем установить маску, чтобы быть линия слоя, как это:

[gradientLayer setMask:lineLayer]; 

Что круто о градиентного слоя, что позволяет чтобы указать список мест, где будет остановлен градиент, чтобы вы могли исчезать и исчезать. Он поддерживает только линейные градиенты, но, похоже, это может соответствовать вашим потребностям.

Дайте мне знать, если вам нужно уточнение.

EDIT: Теперь, когда я думаю об этом, просто создайте единственный CAGradientLayer, который является шириной/высотой линии, которую вы желаете. Укажите цвета градиента (от черного до белого или черного цвета, чтобы очистить цвет) и startPoint и endtPoints, и он должен предоставить вам то, что вам нужно.

+0

Вы правы, это вполне соответствовало бы моим потребностям, но, к сожалению, это доступно только с версией 3 iPhone OS, и я хочу использовать как минимум 2,2. Спасибо, в любом случае... – Walchy

+1

Я предполагаю, что вы имели в виду [gradientLayer setMask: LineLayer]; - правильно? Вы маскируете CAGradientLayer с помощью CAShapeLayer. – Palimondo

+0

Блестящий. Многому научился. – Ian1971

8

После того, как вы рисуете линию, вы можете позвонить

CGContextClip(context); 

клип далее рисунок в вашей области линии. Если вы нарисуете градиент, он должен теперь содержаться в пределах области линии. Обратите внимание, что вам нужно будет использовать чистый цвет для вашей линии, если вы просто хотите, чтобы градиент отображался, а не под ним.

Существует вероятность того, что линия будет слишком тонкой, чтобы ваш градиент отображался, и в этом случае вы можете использовать CGContextAddRect() для определения более толстой области.

Я представляю более подробный пример использования этого контекстного отсечения в моем ответе here.

+1

Я попробовал свое предложение: \t CGContextSetLineWidth (context, 10.0); // должно быть достаточно толстым \t CGContextSetRGBStrokeColor (контекст, 0.0, 0.0, 0.0, 0.0); \t CGContextMoveToPoint (контекст, 50,50); \t CGContextAddLineToPoint (контекст, 100,100); \t CGContextStrokePath (контекст); \t CGContextClip (контекст); \t CGContextDrawLinearGradient (контекст, myGradient, myStartPoint, myEndPoint, 0); но это выбрасывает : doClip: пустая трасса. В документации указано, что CGContextStrokePath (контекст); очищает путь - без этого метода не возникает ошибка, но ничего не рисуется вообще. Любые идеи? – Walchy

0
CGContextMoveToPoint(context, frame.size.width-200, frame.origin.y+10); 
CGContextAddLineToPoint(context, frame.size.width-200, 100-10); 
CGFloat colors[16] = { 0,0, 0, 0, 
    0, 0, 0, .8, 
    0, 0, 0, .8, 
    0, 0,0 ,0 }; 
CGColorSpaceRef baseSpace = CGColorSpaceCreateDeviceRGB(); 
CGGradientRef gradient = CGGradientCreateWithColorComponents(baseSpace, colors, NULL, 4); 

CGContextSaveGState(context); 
CGContextAddRect(context, CGRectMake(frame.size.width-200,10, 1, 80)); 
CGContextClip(context); 
CGContextDrawLinearGradient (context, gradient, CGPointMake(frame.size.width-200, 10), CGPointMake(frame.size.width-200,80), 0); 
CGContextRestoreGState(context); 

его работа для меня.

25

Можно погладить произвольные пути с градиентом или любым другим эффектом заливки, таким как узор.

Как вы нашли, поглаженные пути не отображаются с текущим градиентом. Только заполненные пути используют градиент (когда вы поворачиваете их в клип, а затем нарисуете градиент).

Однако, Core Graphics имеет удивительно прохладное процедуру CGContextReplacePathWithStrokedPath, который преобразует путь, который вы собираетесь инсульта, чтобы путь, который является эквивалента при заполнении.

За кулисами CGContextReplacePathWithStrokedPath формирует краевой многоугольник вокруг вашего пути хода и переключает его на путь, который вы определили. Я бы предположил, что движок рендеринга Core Graphics, вероятно, делает это в любом случае в звонках до CGContextStrokePath.

Вот документация компании Apple на этом:

Кварц создает погладил путь, используя параметры текущего графического контекста. Новый путь создается так, что его заполнение рисует те же пиксели, что и поглаживание исходного пути. Вы можете использовать этот путь так же, как вы используете путь любого контекста. Например, вы можете кликать по поглаженной версии пути, вызывая эту функцию, а затем вызов функции CGContextClip.

Таким образом, преобразовать ваш путь к чему-то вы можете заполнить, превратить это в к клипу, и затем обратить градиент. Эффект будет таким, как если бы вы погладили путь с помощью градиента.

Код

Это будет выглядеть примерно так ...

// Get the current graphics context. 
    // 
    const CGContextRef context = UIGraphicsGetCurrentContext(); 

    // Define your stroked path. 
    // 
    // You can set up **anything** you like here. 
    // 
    CGContextAddRect(context, yourRectToStrokeWithAGradient); 

    // Set up any stroking parameters like line. 
    // 
    // I'm setting width. You could also set up a dashed stroke 
    // pattern, or whatever you like. 
    // 
    CGContextSetLineWidth(context, 1); 

    // Use the magical call. 
    // 
    // It turns your _stroked_ path in to a **fillable** one. 
    // 
    CGContextReplacePathWithStrokedPath(context); 

    // Use the current _fillable_ path in to define a clipping region. 
    // 
    CGContextClip(context); 

    // Draw the gradient. 
    // 
    // The gradient will be clipped to your original path. 
    // You could use other fill effects like patterns here. 
    // 
    CGContextDrawLinearGradient(
     context, 
     yourGradient, 
     gradientTop, 
     gradientBottom, 
     0 
    ); 

Дальнейшие заметки

Стоит подчеркнуть часть вышеуказанной документации:

Quartz создает погладил путь с использованием параметров текущего графического контекста.

Очевидным параметром является ширина линии. Тем не менее, все используется в качестве чертежного состояния линии, например, шаблон хода, предел митры, линейные соединения, колпачки, тире и т. Д. Это делает этот подход чрезвычайно мощным.

Для получения дополнительной информации см. this answer of this S.O. question.