Управление ориентацией паттерна в CGStroke

Я пытаюсь создать в своем приложении эффект «узорчатого мазка кистью». Я добиваюсь этого, используя CGContextStrokePath с узором UIColor. Это дает мне проблему ниже.

Когда я рисую прямую линию, она работает фантастически, например:

введите описание изображения здесь

Но когда я рисую диагональный штрих, я получаю следующее:

введите описание изображения здесь

В то время как я на самом деле к этому стремлюсь:

введите описание изображения здесь

(Проблема здесь в разнице в ориентации узора, а не в моей некачественной обрезке изображения!)

То, что я пытался сделать до сих пор, - это искать способ контролировать ориентацию, в которой узор выложен / отображается, но мне не удалось выяснить способ сделать это. Может ли кто-нибудь просветить меня или сказать, как мне это делать?

Текущий код включен для полноты ниже.

- (void)drawRect:(CGRect)rect
{
    [super drawRect:rect];

    // get the current context
    CGContextRef context = UIGraphicsGetCurrentContext();

    //Create a pattern
    NSString* theFilePath = [[NSBundle mainBundle] pathForResource: @"iceliteTrial.png" ofType: nil];
    UIImage* theGrassPatternImage = [UIImage imageWithContentsOfFile: theFilePath];
    UIColor* iceLitePattern = [UIColor colorWithPatternImage: theGrassPatternImage];
    CGSize phase = CGSizeMake(self.lineStart.x, self.lineStart.y-30);
    CGContextSetPatternPhase(context,phase);

    // set the stroke color and width
    CGContextSetStrokeColorWithColor(context, iceLitePattern.CGColor);
    CGContextSetLineWidth(context, 60.0);

    // move to your first point
    CGContextMoveToPoint(context, self.lineStart.x, self.lineStart.y);

   // add a line to your second point
    CGContextAddLineToPoint(context, self.lineEnd.x, self.lineEnd.y);

    // tell the context to draw the stroked line
    CGContextStrokePath(context);

}

person Chris    schedule 05.02.2014    source источник
comment
Вы делаете [UIImage imageWithContentsOfFile: theFilePath]; каждый раз, когда вызывается draw rect. Это отрицательно скажется на производительности. Вы должны загрузить его один раз при загрузке представления и сохранить его в переменной экземпляра.   -  person 67cherries    schedule 05.02.2014
comment
Хороший крик - спасибо. Прошу прощения - это определенно код в стадии разработки!   -  person Chris    schedule 05.02.2014
comment
Нет проблем. У меня была такая же проблема с загрузкой пользовательских контактов изображения на MKMapView ... с более чем 800 контактами. Я понял это очень быстро :).   -  person 67cherries    schedule 05.02.2014


Ответы (1)


Вместо использования CGContext я бы рекомендовал перейти на использование CAShapeLayer. Я использовал этот подход в одном из своих приложений, например:

//call this on every drawRect: call.
-(void)makeLineLayer:(CALayer *)layer{
    CAShapeLayer *line = [CAShapeLayer layer];
    UIBezierPath *linePath=[UIBezierPath bezierPath];
    [linePath moveToPoint:self.lineStart];
    [linePath addLineToPoint:self.lineEnd];
    [linePath setLineWidth:60.0];

    line.path=linePath.CGPath;
    line.fillColor = nil;
    line.opacity = 1.0;
    [layer addSublayer:line];
}

Это даст вам линию между двумя точками. Отсюда я бы рекомендовал добавить CALayer к CAShapeLayer и установить его свойство contents для вашего изображения. Вот ссылка на статью, описывающую, как разместить изображение в CALayer. Затем вам нужно вычислить угол CAShapeLayer и повернуть CALayer на этот угол.

person 67cherries    schedule 06.02.2014
comment
Спасибо за ответ @ 67cherries, сейчас я изучаю его, но возникли проблемы с его реализацией - я впервые коснулся CALayers. Отправил вопрос по приведенной ниже ссылке с тем, с чем я борюсь, не знаю, сможете ли вы посоветовать и там? stackoverflow.com/q/21608376/1768779 - person Chris; 06.02.2014
comment
Спасибо. В конце концов, я сделал что-то в этом роде, используя CAShapeLayer в качестве маски. Я больше никогда не хочу заниматься тригонометрией! Спасибо за вашу помощь. - person Chris; 15.02.2014