2012-11-24 24 views
7

Aight więc chcę, aby narysować trójkąt tak:Jak narysować trójkąt z zaokrąglonymi narożnikami używając quartz2d/CoreGraphics

rounded triangle

Obecnie używam kombinacji CAShapeLayer i tworząc ścieżkę z a UIBezierPath (kod jest poniżej), a następnie nakładając go jako maskę dla innej warstwy (self.layer, ponieważ jestem w podklasie UIView i zamiast ustawiać warstwę warstwową robię to w ten sposób, aby zachować pierwotną warstwę)

w każdym razie kod:

_bezierPath = [[UIBezierPath bezierPath] retain]; 
#define COS30 0.86602540378 
#define SIN30 0.5 
[_bezierPath moveToPoint:(CGPoint){self.frame.size.width/2.f-r*SIN30,r*COS30}]; 
[_bezierPath addArcWithCenter:(CGPoint){self.frame.size.width/2.f,r*COS30*2.f} radius:r startAngle:2*M_PI/3.f endAngle:M_PI/3.f clockwise:YES]; 
[_bezierPath addLineToPoint:(CGPoint){self.frame.size.width-r*SIN30,self.frame.size.height-r*COS30}]; 
[_bezierPath addArcWithCenter:(CGPoint){self.frame.size.width-r*SIN30-r,self.frame.size.height-r*COS30} radius:r startAngle:0.f endAngle:-M_PI/3.f clockwise:YES]; 
[_bezierPath addLineToPoint:(CGPoint){r*SIN30,self.frame.size.height-r*COS30}]; 
[_bezierPath addArcWithCenter:(CGPoint){r*SIN30+r,self.frame.size.height-r*COS30} radius:r startAngle:4*M_PI/3.f endAngle:M_PI clockwise:YES]; 
[_bezierPath closePath]; 
CAShapeLayer *s = [CAShapeLayer layer]; 
s.frame = self.bounds; 
s.path = _bezierPath.CGPath; 
self.layer.mask = s; 
self.layer.backgroundColor = [SLInsetButton backgroundColorForVariant:SLInsetButtonColorForSLGamePieceColor(_color)].CGColor; 

i niestety wynik nie jest to, czego szukałem, zamiast rogi stają się małe gałki (jakby jej obrócenie zbyt dużo)

góry dziękuję

+0

dlaczego cos (30), a nie 60? – AlexWien

+0

w takim przypadku, do którego się odnosisz? – DanZimm

Odpowiedz

14

genialny przyjaciela (John Heaton w przypadku wpadasz na niego, on jest całkiem niesamowity) przypominał mi właściwości lineCap i lineJoin, w które wkładana jest rdzeniowa grafika.

Gdzieś:

#define border (10.f) 

I w interfejsie:

@property (nonatomic, strong) UIBezierPath *bezierPath; 

I w init utworzyć krótką ścieżkę tak:

CGFloat inset = border/2.f; 
UIBezierPath *bezierPath = [UIBezierPath bezierPath]; 
[bezierPath moveToPoint:(CGPoint){ self.frame.size.width/2.f, inset }]; 
[bezierPath addLineToPoint:(CGPoint){ self.frame.size.width - inset, self.frame.size.height - inset }]; 
[bezierPath addLineToPoint:(CGPoint){ a, self.frame.size.height - a }]; 
[bezierPath closePath]; 

self.bezierPath = bezierPath; 

a potem w swojej metodzie drawRect: wykonaj następujące czynności:

CGContextRef c = UIGraphicsGetCurrentContext(), context = c; 
CGColorRef col = [UIColor redColor].CGColor; 
CGColorRef bcol = [UIColor redColor].CGColor; 
CGContextSetFillColorWithColor(c, col); 
CGContextSetStrokeColorWithColor(c, bcol); 
CGContextSetLineWidth(c, border); 
CGContextSetLineJoin(c, kCGLineJoinRound); 
CGContextSetLineCap(c, kCGLineCapRound); 
CGContextAddPath(c, self.bezierPath.CGPath); 
CGContextStrokePath(c); 
CGContextAddPath(c, self.bezierPath.CGPath); 
CGContextFillPath(c); 

I że właściwie daje zaokrąglone narożniki na trójkącie, również z opcją mieć obramowanie lub nakreślić

+0

Zastanów się nad zamianą '# define' na' const'! –

+0

Wybrałem użycie makra w przeciwieństwie do czegoś w rodzaju 'static const', ponieważ nie musisz odnosić się do liczby ze wskaźnikiem w historii, dodatkowe sprawdzanie typu jest tutaj niepotrzebne (jest używane w jednej procedurze, która zakłada, że ​​jest to float) i otwiera możliwość dostarczenia tej stałej w czasie kompilacji za pomocą cli args lub w konfiguracji xcode (ofc nazwa 'border' nie jest najlepsza i powinna zostać zmieniona, ale ten kod nie powinien po prostu kopiować/wklejony i powinien zostać przeczytany i przemyślany). – DanZimm

+0

Rozumiem, ale czy cały projekt nie jest ponownie rekompilowany, jeśli makro zostało zmienione? –

Powiązane problemy