Se si vuole tracciare il tracciato sottratto, si è da soli. Apple non fornisce un'API che restituisce (o semplicemente tratti) la sottrazione di un percorso da un altro.
Se si desidera solo riempire il percorso sottratto (come nell'immagine di esempio), è possibile farlo utilizzando il tracciato di ritaglio. Devi usare un trucco, però. Quando aggiungi un tracciato al tracciato di ritaglio, il nuovo tracciato di ritaglio è l'intersezione del vecchio percorso di ritaglio e il percorso aggiunto. Quindi, se si aggiunge smallMaskPath
al tracciato di ritaglio, si finisce per riempire solo la regione all'interno di smallMaskPath
, che è l'opposto di ciò che si desidera.
Quello che devi fare è intersecare il tracciato di ritaglio esistente con inverso di smallMaskPath
. Fortunatamente, puoi farlo abbastanza facilmente usando la regola di avvolgimento pari-dispari. Puoi leggere la regola pari pari a Quartz 2D Programming Guide.
L'idea di base è creare un percorso composto con due sottotracciati: il tuo smallMaskPath
e un rettangolo enorme che racchiude completamente il tuo smallMaskPath
e ogni altro pixel che potresti voler riempire. A causa della regola pari, ogni pixel all'interno di smallMaskPath
verrà considerato come esterno al percorso composto e ogni pixel esterno a smallMaskPath
verrà considerato all'interno del percorso composto.
Quindi creiamo questo percorso composto. Inizieremo con l'enorme rettangolo.E non c'è rettangolo più grande rispetto al rettangolo di infinito:
UIBezierPath *clipPath = [UIBezierPath bezierPathWithRect:CGRectInfinite];
Ora facciamo in un tracciato composto con l'aggiunta di smallMaskPath
ad esso:
[clipPath appendPath:smallMaskPath];
Poi abbiamo impostato il percorso per utilizzare il modo uguale su ogni regola dispari:
clipPath.usesEvenOddFillRule = YES;
Prima di clip a questo percorso, dovremmo salvare lo stato grafico in modo da poter annullare la modifica al tracciato di ritaglio quando abbiamo finito:
CGContextSaveGState(UIGraphicsGetCurrentContext()); {
Ora possiamo modificare il tracciato di ritaglio:
[clipPath addClip];
e possiamo riempire bigMaskPath
:
[[UIColor orangeColor] setFill];
[bigMaskPath fill];
Infine ripristinare lo stato grafico, annullare la modifica al tracciato di ritaglio:
} CGContextRestoreGState(UIGraphicsGetCurrentContext());
Ecco il co de tutti insieme nel caso in cui si desidera copiare/incollare:
UIBezierPath *clipPath = [UIBezierPath bezierPathWithRect:CGRectInfinite];
[clipPath appendPath:smallMaskPath];
clipPath.usesEvenOddFillRule = YES;
CGContextSaveGState(UIGraphicsGetCurrentContext()); {
[clipPath addClip];
[[UIColor orangeColor] setFill];
[bigMaskPath fill];
} CGContextRestoreGState(UIGraphicsGetCurrentContext());
Questo è il modo più lavoro di quanto è necessario. È semplice creare un tracciato composto da rotte interne ed esterne e riempirlo con la regola pari. Non è necessario fare nulla per il percorso della clip. – NSResponder
La tua risposta è più semplice quando smallMaskPath è interamente contenuto da bigPathMask, come nell'esempio di Jaden10. Nel caso generale in cui smallMaskPath include anche pixel esterni a bigMaskPath, il tuo approccio più semplice non funzionerà. –
Mi piace lo stile che usi per mettere il GState tra parentesi !! – To1ne