UIView CGGradient обрезается до нарисованной "рамки" - PullRequest
2 голосов
/ 03 октября 2010

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

Я получил несколько подсказок из некоторых постов по теме:

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

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

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

Мой вопрос для этого является двойным

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

Вот моя функция рисования:

- (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]; 

1 Ответ

3 голосов
/ 24 октября 2010

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

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

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

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

Также не забудьте сохранить и восстановить свой контекст до и после выполнения любого отсечения

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

...