2013-08-22 14 views
16

Sto provando a trovare un modo per disegnare una forma di "squircle" dell'icona di iOS 7 in modo programmatico, utilizzando la grafica di base. Non sto chiedendo come disegnare un rettangolo arrotondato. Uno squircle è un superelipse:Disegna programmaticamente lo squircle iOS 7

Squircle

che è leggermente diverso da un normale rettangolo arrotondato: Rounded rectangle vs squircle

Music icon in squircle

È formula esatta is readily available. Tuttavia, non riesco a capire come disegnare questo usando, per esempio, un CGPath, per non parlare di riempirlo, ed essere in grado di ridimensionarlo piuttosto facilmente. Tutto questo pur essendo del tutto esatto con la formula. Qualche idea?

+0

No, so come creare un rettangolo arrotondato; Sono davvero un superellisis di tipo squircle, che usano per le icone trampolino su iOS 7. –

+2

@RemyVanherweghem Il metodo 'bezierPathWithRoundedRect' è stato modificato in iOS 7 per disegnare angoli più fluidi. Inoltre non sembra essere uno squircle: http://blog.mikeswanson.com/post/62341902567/unleashing-genetic-algorithms-on-the-ios-7-icon – millimoose

+0

(Ciò detto, i metodi 'UIBezierPath' non producono una corrispondenza perfetta con il modello di icona, sono solo più vicini di quanto non fossero prima). – millimoose

risposta

12

citazione da Wikipedia: Superellipse

Per n = 1/2, in particolare, ciascuno dei quattro archi è una curva quadratica Bézier definito dai due assi; di conseguenza, ogni arco è un segmento di una parabola.

Quindi, perché non provare ad approssimare Squircle usando le curve di Bezier? Entrambe le curve (Bezier e Squircle) sono definite dalle equazioni parametriche.

UIBezierPath Class hanno Metodo: addCurveToPoint:controlPoint1:controlPoint2:

Aggiunge una curva di Bézier cubica al percorso del ricevitore.

NOTA: l'utilizzo del metodo addQuadCurveToPoint:controlPoint: dà risultati peggiori, verificati.

Ho usato questo metodo e questo è quello che è successo in seguito:

red line - rettangolo arrotondato, blue line - rettangolo da quattro zampe curve di Bezier

Rounded rectangle vs cubic Bezier curve

Se questo risultato è interessato - disegno codice qui sotto .

NOTA: per ottenere una corrispondenza più esatta, è possibile che la curva di Bezier cambi le coordinate dei quattro corner points (ora corrispondono agli angoli del rettangolo in cui è inscritta la figura).

CGContextRef context = UIGraphicsGetCurrentContext(); 
CGContextSaveGState(context); 

//set rect size for draw 
float rectSize = 275.; 
CGRect rectangle = CGRectMake(CGRectGetMidX(rect) - rectSize/2, CGRectGetMidY(rect) - rectSize/2, rectSize, rectSize); 

//Rounded rectangle 
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor); 
UIBezierPath* roundedPath = [UIBezierPath bezierPathWithRoundedRect:rectangle cornerRadius:rectSize/4.7]; 
[roundedPath stroke]; 

//Rectangle from Fours Bezier Curves 
CGContextSetStrokeColorWithColor(context, [UIColor blueColor].CGColor); 
UIBezierPath *bezierCurvePath = [UIBezierPath bezierPath]; 

//set coner points 
CGPoint topLPoint = CGPointMake(CGRectGetMinX(rectangle), CGRectGetMinY(rectangle)); 
CGPoint topRPoint = CGPointMake(CGRectGetMaxX(rectangle), CGRectGetMinY(rectangle)); 
CGPoint botLPoint = CGPointMake(CGRectGetMinX(rectangle), CGRectGetMaxY(rectangle)); 
CGPoint botRPoint = CGPointMake(CGRectGetMaxX(rectangle), CGRectGetMaxY(rectangle)); 

//set start-end points 
CGPoint midRPoint = CGPointMake(CGRectGetMaxX(rectangle), CGRectGetMidY(rectangle)); 
CGPoint botMPoint = CGPointMake(CGRectGetMidX(rectangle), CGRectGetMaxY(rectangle)); 
CGPoint topMPoint = CGPointMake(CGRectGetMidX(rectangle), CGRectGetMinY(rectangle)); 
CGPoint midLPoint = CGPointMake(CGRectGetMinX(rectangle), CGRectGetMidY(rectangle)); 

//Four Bezier Curve 
[bezierCurvePath moveToPoint:midLPoint]; 
[bezierCurvePath addCurveToPoint:topMPoint controlPoint1:topLPoint controlPoint2:topLPoint]; 
[bezierCurvePath moveToPoint:midLPoint]; 
[bezierCurvePath addCurveToPoint:botMPoint controlPoint1:botLPoint controlPoint2:botLPoint]; 
[bezierCurvePath moveToPoint:midRPoint]; 
[bezierCurvePath addCurveToPoint:topMPoint controlPoint1:topRPoint controlPoint2:topRPoint]; 
[bezierCurvePath moveToPoint:midRPoint]; 
[bezierCurvePath addCurveToPoint:botMPoint controlPoint1:botRPoint controlPoint2:botRPoint]; 

[bezierCurvePath stroke]; 

CGContextRestoreGState(context); 
+0

Ottima risposta. Grazie! –

2

Questa non è una grande risposta in quanto non arrivare al cuore di quello che stai chiedendo che è come disegnare un superellisse ** a livello di codice, ma si può:

  1. Scarica lo SVG per l'icona di forma iOS7 qui: http://dribbble.com/shots/1127699-iOS-7-icon-shape-PSD
  2. importarlo al progetto Xcode
  3. Aggiungi PocketSVG al progetto: https://github.com/arielelkin/PocketSVG
  4. Caricare il formato SVG, e convertirlo in un UIBezierPath, da lì si può scalare e trasformare comunque ti piace:

    PocketSVG *myVectorDrawing = [[PocketSVG alloc] initFromSVGFileNamed:@"iOS_7_icon_shape"]; 
    
    UIBezierPath *myBezierPath = myVectorDrawing.bezier; 
    
    // Apply your transforms here: 
    [myBezierPath applyTransform:CGAffineTransformMakeScale(2.5, 2.5)]; 
    [myBezierPath applyTransform:CGAffineTransformMakeTranslation(10, 50)]; 
    
    CAShapeLayer *myShapeLayer = [CAShapeLayer layer]; 
    myShapeLayer.path = myBezierPath.CGPath; 
    myShapeLayer.strokeColor = [[UIColor redColor] CGColor]; 
    myShapeLayer.lineWidth = 2; 
    myShapeLayer.fillColor = [[UIColor clearColor] CGColor]; 
    
    [self.view.layer addSublayer:myShapeLayer]; 
    

** E 'forse la pena notare che la forma potrebbe non essere un superellisse precisa in ogni caso: http://i.imgur.com/l0ljVRo.png

0

Questo sarebbe abbastanza facile da fare in OpenGL ES con uno shader. Basta disegnare un quad e passare in xey come attributi del vertice. Nello shader del frammento, inserisci xey nell'equazione. Se il risultato è < = 1, il frammento si trova all'interno della forma. Se riesco a prendere un po 'di tempo libero, potrei provare questo e postarlo qui.

Se si desidera utilizzare CGPath, penso che la chiave sia di parametrizzare xey in termini di t, che va da 0 a 2π. Quindi valutare xey a intervalli regolari. Cercherò di capirlo anche nel mio tempo libero, ma la mia matematica è piuttosto arrugginita.

BTW, sono certo che Apple è non utilizzando questa formula. Vedere il link che @millimoose postato: http://blog.mikeswanson.com/post/62341902567/unleashing-genetic-algorithms-on-the-ios-7-icon