UIView CGGradient обрезается по нарисованному фрейму

Я пытаюсь сделать более сложный рисунок фона UILabels (или UIView, помещая UILabel сверху, если это необходимо). Поскольку я хочу, чтобы это изменялось автоматически, когда пользователь меняет ориентацию iPhone, я пытаюсь реализовать это в функции drawRect подклассов. Я хотел бы иметь возможность настроить все это в коде, исключив необходимость в изображениях шаблонов, если это возможно.

Я получил некоторые подсказки из некоторых предыдущих сообщений по этой теме:

Градиенты в UIView и UILabels на iPhone и Сделать фон UIView градиентом без подкласса

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

Альтернативой было бы использование CAGradientLayer, который, кажется, работает неплохо, но для этого потребуется некоторое изменение размера кадра при вращении, а слой градиента, кажется, рисует поверх текста, как бы я ни старался.

У меня двоякий вопрос

  • Как изменить приведенный ниже код, чтобы сделать градиентный клип на нарисованную «рамку»
  • Как мне заставить CAGradientLayer рисовать за текстом UILabel (или мне нужно поместить UIView за UILabel с CAGradientLayer в качестве фона)

Вот моя функция drawrect:

- (void)drawRect:(CGRect)rect {
// Drawing code
CGContextRef c = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(c, [[UIColor clearColor] CGColor]);
CGContextSetStrokeColorWithColor(c, [strokeColor CGColor]);
CGContextSetLineWidth(c, 1);

CGFloat minx = CGRectGetMinX(rect), midx = CGRectGetMidX(rect), maxx = CGRectGetMaxX(rect) ;
CGFloat miny = CGRectGetMinY(rect), midy = CGRectGetMidY(rect), maxy = CGRectGetMaxY(rect) ;
minx = minx + 1;
miny = miny + 1;

maxx = maxx - 1;
maxy = maxy - 1;

CGGradientRef glossGradient;
CGColorSpaceRef rgbColorspace;
size_t num_locations = 2;
CGFloat locations[2] = { 0.0, 1.0 };
CGFloat components[8] = { 0.6, 0.6, 0.6, 1.0,  // Start color
0.3, 0.3, 0.3, 1.0 }; // End color

rgbColorspace = CGColorSpaceCreateDeviceRGB();
glossGradient = CGGradientCreateWithColorComponents(rgbColorspace, components, locations, num_locations);

CGRect currentBounds = [self bounds];
CGPoint topCenter = CGPointMake(CGRectGetMidX(currentBounds), 0.0f);
CGPoint midCenter = CGPointMake(CGRectGetMidX(currentBounds),            CGRectGetMidY(currentBounds));
CGPoint lowCenter = CGPointMake(CGRectGetMidX(currentBounds), CGRectGetMidY(currentBounds));

CGContextDrawLinearGradient(c, glossGradient, topCenter, midCenter, 0);

CGGradientRelease(glossGradient);
CGColorSpaceRelease(rgbColorspace); 

CGContextMoveToPoint(c, minx, midy);
CGContextAddArcToPoint(c, minx, miny, midx, miny, ROUND_SIZE_INFO);
CGContextAddArcToPoint(c, maxx, miny, maxx, midy, ROUND_SIZE_INFO);
CGContextAddArcToPoint(c, maxx, maxy, midx, maxy, ROUND_SIZE_INFO);
CGContextAddArcToPoint(c, minx, maxy, minx, midy, ROUND_SIZE_INFO);

// Close the path
CGContextClosePath(c);
// Fill & stroke the path
CGContextDrawPath(c, kCGPathFillStroke);                
//        return;  

[super drawRect: rect]; 

person jollyCocoa    schedule 03.10.2010    source источник
comment
В принципе, я хотел бы знать, есть ли способ ограничить градиент определенной границей, немного похожий на флаг maskToBounds в CALayer.   -  person jollyCocoa    schedule 03.10.2010
comment
Использование CAGradientLayer кажется подходящим для решения простых прямоугольных градиентных фонов, но остается вопрос, можно ли выполнить ту же задачу с пользовательским рисунком ... (что, если, например, я хотел бы нарисовать пользовательский фон с не квадратной рамкой, используя CGContextAddLineToPoint () и CGContextAddArcToPoint (). Можно ли заполнить содержимое границы градиентом и как это сделать)?   -  person jollyCocoa    schedule 04.10.2010


Ответы (1)


То, что вы ищете, это CGContextClip ()

Создайте свой путь и градиент, как в вашем коде, а затем

CGContextClip(c);
CGContextDrawLinearGradient(c, glossGradient, topCenter, midCenter, 0);
CGGradientRelease(glossGradient);

(Удалите старый вызов CGContextDrawLinearGradient)

Также не забудьте сохранить и восстановить свой контекст до и после обрезки.

Если ваш вырез инвертирован по сравнению с тем, что вы хотите, попробуйте CGContextEOClip () (или нарисуйте свой путь в обратном порядке)

person Olof Hedman    schedule 24.10.2010
comment
Спасибо, я займусь этим как можно скорее! - person jollyCocoa; 28.10.2010
comment
Я возвращаюсь к этой теме. Прошло много времени, и я надеюсь, вы прочитаете это. Мне удалось создать градиент с обрезанными границами в соответствии с путем, но у меня все еще есть проблема, которую я не смог решить. В приведенном выше коде я создаю контур прямоугольника с закругленными углами. В исходном чертеже это привело к фигуре с нарисованной границей и другим цветом заливки. Теперь я хочу добавить к этой фигуре собственный градиент. Проблема в том, что ваше исправление позволяет мне рисовать исходную форму с необрезанным градиентом выше или только градиент, обрезанный по контуру. Итак, как мне добиться того и другого? - person jollyCocoa; 23.01.2011
comment
Я решил это. Решение заключалось в том, чтобы нарисовать новый путь после того, как был пройден первый путь. Большое спасибо! - person jollyCocoa; 23.01.2011