2009-04-22 6 views
2

En tant qu'arrière-plan pour l'une des vues de mon application, je voudrais dessiner une bordure rectangulaire assez simple juste à l'intérieur de son cadre. Ce serait essentiellement un dégradé rectangulaire: une ligne noire entourant le cadre, devenant blanche à environ 10-20 pixels. Malheureusement, autant que je sache, Core Graphics ne fournit pas de dégradés rectangulaires (CGGradient ou CGShading). Je me demande donc quelle serait la meilleure approche.La meilleure façon d'accomplir ce dessin avec Quartz 2D/Core Graphics?

Deux qui se produisent pour moi:

  1. dessiner une série de rectangles concentriques, chacun de couleur plus claire ultérieurement, et encadré par 1px de chaque côté. Je ne peux pas penser à une approche plus simple, mais je dois faire tous les calculs de gradient moi-même, et il pourrait y avoir beaucoup d'opérations graphiques. Utiliser CGGradient en mode linéaire, une fois de chaque côté. Mais pour que cela fonctionne, je pense que je devrais d'abord mettre en place une zone de détourage trapézoïdale pour chaque côté, afin que les dégradés soient coupés en onglet.

On dirait que il devrait être un moyen d'utiliser semblent chemin caresser pour le faire, mais il n'a pas comme il y a un moyen de définir un modèle qui est orienté différemment de chaque côté.

+0

L'utilisation d'un CGGradient pour chaque bord sera plus rapide, mais vous pouvez utiliser un UIImage comme cache si c'est encore trop lent (attirer l'UIImage une fois, puis dessiner l'image sur la vue en cas de besoin) – rpetrich

+0

Oui , Je pense que peu importe l'approche que je prends au dessin, la mise en cache d'une image avec les résultats va probablement être une bonne idée. Mais j'aime bien l'idée de faire le dessin procédural, plutôt que d'expédier un PNG dans l'application. –

Répondre

3

Je voudrais aller avec l'option # 2:

Utilisez CGGradient en mode linéaire, une fois de chaque côté. Mais pour que cela fonctionne, je pense que je devrais d'abord mettre en place une zone de détourage trapézoïdale pour chaque côté, afin que les dégradés soient coupés en onglet.

En utilisant NSBezierPath pour créer les régions de forme trapézoïdale serait assez simple, et vous ne devez effectuer quatre opérations de dessin.

Voici le code de base pour la création de la zone trapézoïdale côté gauche:

NSRect outer = [self bounds]; 
NSPoint outerPoint[4]; 
outerPoint[0] = NSMakePoint(0, 0); 
outerPoint[1] = NSMakePoint(0, outer.size.height); 
outerPoint[2] = NSMakePoint(outer.size.width, outer.size.height); 
outerPoint[3] = NSMakePoint(outer.size.width, 0); 

NSRect inner = NSInsetRect([self bounds], borderSize, borderSize); 
NSPoint innerPoint[4]; 
innerPoint[0] = inner.origin; 
innerPoint[1] = NSMakePoint(inner.origin.x, 
          inner.origin.y + inner.size.height); 
innerPoint[2] = NSMakePoint(inner.origin.x + inner.size.width, 
          inner.origin.y + inner.size.height); 
innerPoint[3] = NSMakePoint(inner.origin.x + inner.size.width, 
          inner.origin.y); 

NSBezierPath leftSidePath = [[NSBezierPath bezierPath] retain]; 
[leftSidePath moveToPoint:outerPoint[0]]; 
[leftSidePath lineToPoint:outerPoint[1]]; 
[leftSidePath lineToPoint:innerPoint[1]]; 
[leftSidePath lineToPoint:innerPoint[0]]; 
[leftSidePath lineToPoint:outerPoint[0]]; 

// ... etc. 

[leftSidePath release]; 
+0

En parlant comme quelqu'un qui (évidemment?) N'a pas fait beaucoup de programmation graphique sur l'iPhone (ou Mac) encore ... y a-t-il une raison de préférer NSBezierPath? La plupart des exemples que j'ai vus se concentrent sur les API Core Graphics. –

+0

Eh bien, je l'ai utilisé ici parce que je l'ai déjà utilisé, alors sachez que cela fonctionne. :) Il est tout à fait possible que Core Graphics puisse le faire mieux. Pas de mal à faire un essai, mais assurez-vous de profiler votre code pour voir si vous obtenez une augmentation de performance mesurable (ou si vous en avez réellement besoin, d'ailleurs). –

+0

Ce n'est pas exactement le code que j'ai fini avec, mais c'est petit semblable. Je n'ai jamais trouvé une meilleure solution que de dessiner quatre trapèzes. –

0

quelque chose comme ça pourrait aussi fonctionner. fondamentalement: au lieu d'utiliser des chemins de détourage, utilisez simplement blendmode. et dans cet exemple, le dégradé est mis en cache dans un CGLayer.

CGContextRef ctx = UIGraphicsGetCurrentContext(); 
CGColorSpaceRef cspace = CGColorSpaceCreateDeviceRGB(); 

CGContextSetRGBFillColor(ctx, 1.0, 1.0, 1.0, 1.0); 
CGContextFillRect(ctx,self.bounds); 

CGFloat w = self.bounds.size.width; 
CGFloat h = self.bounds.size.height; 
CGFloat dh = (w-h)/2; 

CGLayerRef l = CGLayerCreateWithContext(ctx,CGSizeMake(h,48.0f),NULL); 
CGContextRef lctx = CGLayerGetContext(l); 

float comp[] = { .2,.5,1.0,1.0,1.0,1.0,1.0,1.0}; 
CGGradientRef gradient = CGGradientCreateWithColorComponents(cspace, comp, NULL, 2); 
CGContextDrawLinearGradient(lctx, gradient,CGPointMake(0,0),CGPointMake(0,48), 0); 

CGContextSaveGState(ctx); 
CGContextSetBlendMode(ctx,kCGBlendModeDarken); 
for(int n=1;n<5;n++) 
{ 
    CGContextTranslateCTM(ctx,w/2.0,h/2.0); 
    CGContextRotateCTM(ctx, M_PI_2); 
    CGContextTranslateCTM(ctx,-w/2.0,-h/2.0); 
    CGContextDrawLayerAtPoint(ctx,CGPointMake((n%2)*dh,(n%2)*-dh),l); 
} 
CGContextRestoreGState(ctx); 
Questions connexes