Tout ce dont vous avez besoin est couvert dans le Quartz 2D Guide de Programmation. Je vous suggère de regarder à travers elle.
Cependant, il peut être difficile de mettre tout cela ensemble, donc je vais vous guider à travers elle. Nous allons écrire une fonction qui prend une taille et renvoie une image qui ressemble à peu près à l'un de vos segments:
Nous commençons la définition de la fonction comme ceci:
static UIImage *imageWithSize(CGSize size) {
Nous aurons besoin d'une constante de l'épaisseur du segment:
static CGFloat const kThickness = 20;
et une constante pour la largeur de la ligne décrivant le segment:
static CGFloat const kLineWidth = 1;
et une constante pour la taille de l'ombre:
static CGFloat const kShadowWidth = 8;
Ensuite, nous devons créer une image contexte dans lequel dessiner:
UIGraphicsBeginImageContextWithOptions(size, NO, 0); {
J'ai mis une accolade gauche sur la fin de la ligne, parce que j'aime un niveau supplémentaire de retrait pour me rappeler d'appeler UIGraphicsEndImageContext
plus tard.
Depuis beaucoup de fonctions dont nous avons besoin à l'appel sont des Graphiques de Base (aka Quartz 2D) de fonctions, de ne pas UIKit fonctions, nous devons obtenir de l' CGContext
:
CGContextRef gc = UIGraphicsGetCurrentContext();
Nous sommes maintenant prêts à vraiment commencer. Nous avons d'abord ajouter un arc pour le chemin d'accès. L'arc court le long du centre du segment nous voulons attirer l':
CGContextAddArc(gc, size.width / 2, size.height / 2,
(size.width - kThickness - kLineWidth) / 2,
-M_PI / 4, -3 * M_PI / 4, YES);
Maintenant, nous allons demander Graphiques de Base pour remplacer le chemin d'accès avec une "caresse", version qui décrit le chemin d'accès. Nous avons d'abord définir l'épaisseur du trait à l'épaisseur de la nous voulons le segment d'avoir:
CGContextSetLineWidth(gc, kThickness);
et nous avons défini la ligne de casquette style "bout à bout" de sorte que nous allons carré-off se termine:
CGContextSetLineCap(gc, kCGLineCapButt);
Ensuite, nous pouvons nous demander Graphiques de Base pour remplacer le chemin d'accès avec un caressa version:
CGContextReplacePathWithStrokedPath(gc);
Pour remplir ce chemin avec un dégradé linéaire, nous devons le dire Graphiques de Base à clip toutes les opérations à l'intérieur de la trajectoire. Cela permettra de faire des Graphiques de Base réinitialiser le chemin, mais nous allons avoir besoin de le chemin plus tard pour dessiner la ligne noire autour du bord. Donc, nous allons copier le chemin d'accès ici:
CGPathRef path = CGContextCopyPath(gc);
Puisque nous voulons que le segment de jeter une ombre, nous allons mettre l'ombre des paramètres avant de nous faire un dessin:
CGContextSetShadowWithColor(gc,
CGSizeMake(0, kShadowWidth / 2), kShadowWidth / 2,
[UIColor colorWithWhite:0 alpha:0.3].CGColor);
Nous allons à la fois de combler le segment (avec un dégradé) et d'accident vasculaire cérébral (pour dessiner le contour noir). Nous voulons une seule ombre pour les deux opérations. Nous dire Graphiques de Base qu'en commençant par une couche de transparence:
CGContextBeginTransparencyLayer(gc, 0); {
J'ai mis une accolade gauche sur la fin de la ligne, parce que j'aime avoir un niveau d'indentation pour me rappeler d'appeler CGContextEndTransparencyLayer
plus tard.
Puisque nous allons modifier le contexte du clip de la région pour le remplissage, mais nous ne voulons pas de saturation lorsque nous caresser le contour plus tard, nous avons besoin d'enregistrer l'état graphique:
CGContextSaveGState(gc); {
J'ai mis une accolade gauche sur la fin de la ligne, parce que j'aime avoir un niveau d'indentation pour me rappeler d'appeler CGContextRestoreGState
plus tard.
Pour combler le chemin avec un dégradé, nous avons besoin de créer un objet de dégradé:
CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient = CGGradientCreateWithColors(rgb, (__bridge CFArrayRef)@[
(__bridge id)[UIColor grayColor].CGColor,
(__bridge id)[UIColor whiteColor].CGColor
], (CGFloat[]){ 0.0f, 1.0f });
CGColorSpaceRelease(rgb);
Nous avons également besoin de trouver un point de départ et un point de fin du dégradé. Nous allons utiliser le chemin d'accès de la boîte englobante:
CGRect bbox = CGContextGetPathBoundingBox(gc);
CGPoint start = bbox.origin;
CGPoint end = CGPointMake(CGRectGetMaxX(bbox), CGRectGetMaxY(bbox));
et nous allons la force du gradient à tirer horizontalement ou verticalement, selon la plus longue:
if (bbox.size.width > bbox.size.height) {
end.y = start.y;
} else {
end.x = start.x;
}
Maintenant, enfin, nous avons tout ce dont nous avons besoin pour tracer le dégradé. Nous avons d'abord clip pour le chemin d'accès:
CGContextClip(gc);
Puis nous tracer le dégradé:
CGContextDrawLinearGradient(gc, gradient, start, end, 0);
Ensuite, nous pouvons libérer le gradient et de restaurer les sauvés de l'état graphique:
CGGradientRelease(gradient);
} CGContextRestoreGState(gc);
Lorsque nous les avons appelés CGContextClip
, Graphiques de Base réinitialiser le contexte du chemin. Le chemin n'est pas une partie de l'sauvé de l'état graphique; c'est pourquoi nous avons fait une copie plus tôt. Il est temps maintenant d'utiliser cette copie pour définir le chemin d'accès dans le contexte nouveau:
CGContextAddPath(gc, path);
CGPathRelease(path);
Maintenant, nous pouvons avc le chemin, pour dessiner le contour noir du segment:
CGContextSetLineWidth(gc, kLineWidth);
CGContextSetLineJoin(gc, kCGLineJoinMiter);
[[UIColor blackColor] setStroke];
CGContextStrokePath(gc);
Ensuite nous dire Graphiques de Base pour mettre fin à la transparence de la couche. Cela permettra de regarder ce que nous avons dessiné et ajouter de l'ombre en-dessous:
} CGContextEndTransparencyLayer(gc);
Maintenant, nous sommes tous fait de dessin. Nous demandons UIKit pour créer un UIImage
de l'image contexte, détruire le contexte et le retour de l'image:
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return image;
}
Vous pouvez trouver le code tous ensemble dans ce résumé.