Dessiner un quadrillage de style iOS 7 de façon programmatique
j'essaie de trouver un moyen de dessiner une icône de style iOS 7 'squircle' de forme programmatique, en utilisant des graphismes de base. Je ne demande pas comment dessiner un rectangle arrondi. Un squircle est un superellipse:
qui est légèrement différent d'un rectangle arrondi régulier:
c'est la formule exacte est facilement disponible. Cependant, je ne peux pas comprendre comment dessiner ce en utilisant, par exemple, un CGPath, sans parler de le remplir, et pouvoir le redimensionner assez facilement. Tout cela tout en étant entièrement exacte avec la formule.
4 réponses
citation tirée de Wikipedia: Superellipse
Pour n = 1/2, en particulier, chacun des quatre arcs est un courbe de Bézier quadratique défini par les deux axes; par conséquent, chaque arc est un segment de parabole.
alors pourquoi ne pas essayer de faire une approximation de la courbe de Squircle en utilisant des courbes de Bezier? Les deux courbes (Bezier et Squircle) sont définies par les équations paramétriques.
Classe UIBezierPath méthode: addCurveToPoint:controlPoint1:controlPoint2:
ajoute une courbe de Bézier cubique à la trajectoire du récepteur.
NOTE: Utilisation du
j'ai utilisé cette méthode et c'est ce qui s'est passé comme résultat:
red line
- rectangle arrondi,blue line
- rectangle à partir de 4 courbes de Bezier
si ce résultat est intéressé-code de dessin ci-dessous.
NOTE: pour obtenir un résultat plus précis match courbe de Bezier peut être nécessaire pour changer les coordonnées des quatre corner points
(maintenant, ils correspondent aux angles du rectangle dans lequel s'inscrit la figure).
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);
une version remplie de la réponse acceptée, également portée à Swift:
override func draw(_ rect: CGRect) {
super.draw(rect)
guard let context = UIGraphicsGetCurrentContext() else {
return
}
context.saveGState()
let rect = self.bounds
let rectSize: CGFloat = rect.width
let rectangle = CGRect(x: rect.midX - rectSize / 2, y: rect.midY - rectSize / 2, width: rectSize, height: rectSize)
let topLPoint = CGPoint(x: rectangle.minX, y: rectangle.minY)
let topRPoint = CGPoint(x: rectangle.maxX, y: rectangle.minY)
let botLPoint = CGPoint(x: rectangle.minX, y: rectangle.maxY)
let botRPoint = CGPoint(x: rectangle.maxX, y: rectangle.maxY)
let midRPoint = CGPoint(x: rectangle.maxX, y: rectangle.midY)
let botMPoint = CGPoint(x: rectangle.midX, y: rectangle.maxY)
let topMPoint = CGPoint(x: rectangle.midX, y: rectangle.minY)
let midLPoint = CGPoint(x: rectangle.minX, y: rectangle.midY)
let bezierCurvePath = UIBezierPath()
bezierCurvePath.move(to: midLPoint)
bezierCurvePath.addCurve(to: topMPoint, controlPoint1: topLPoint, controlPoint2: topLPoint)
bezierCurvePath.addCurve(to: midRPoint, controlPoint1: topRPoint, controlPoint2: topRPoint)
bezierCurvePath.addCurve(to: botMPoint, controlPoint1: botRPoint, controlPoint2: botRPoint)
bezierCurvePath.addCurve(to: midLPoint, controlPoint1: botLPoint, controlPoint2: botLPoint)
context.setFillColor(UIColor.lightGray.cgColor)
bezierCurvePath.fill()
context.restoreGState()
}
parfait pour une utilisation dans une sous-classe uivi.
ce n'est pas une bonne réponse car il ne va pas au cœur de ce que vous demandez qui est la façon de dessiner un superellipse** programmatiquement, mais vous pouvez:
- Téléchargez la SVG pour la forme de l'icône iOS7 ici:http://dribbble.com/shots/1127699-iOS-7-icon-shape-PSD
- Importer dans votre projet Xcode
- ajouter PocketSVG à votre projet:https://github.com/arielelkin/PocketSVG
charger le SVG, et convertissez-le en UIBezierPath, à partir de là, vous pouvez le dimensionner et le transformer comme bon vous semble:
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];
** il est peut-être intéressant de noter que la forme pourrait ne pas être une superellipse exacte de toute façon: http://i.imgur.com/l0ljVRo.png
ce serait assez facile à faire dans OpenGL ES avec un shader. Il suffit de dessiner un quad et de passer dans les X et y comme attributs de vertex. Dans le fragment shader, insérez x et y dans l'équation. Si le résultat <= 1, alors le fragment est à l'intérieur de la forme. Si je peux avoir un peu de temps libre je pourrais essayer ceci et le poster ici.
si vous voulez utiliser CGPath, je pense que la clé est de paramétrer x et y en termes de t, qui va de 0 à 2π. Ensuite, évaluez x et y à intervalles réguliers. Je vais essayer de comprendre cela dans mon temps libre, aussi, mais mon calcul est un peu rouillé.
BTW, je suis certain qu'Apple est en utilisant cette formule. Voir le lien que @millimoose a posté: http://blog.mikeswanson.com/post/62341902567/unleashing-genetic-algorithms-on-the-ios-7-icon