J'ai un UIView
ajouté dans le code au moment de l'exécution.
Je veux y dessiner un UIBezierPath
, mais cela signifie-t-il que je dois remplacer le drawRect
pour UIView?
Ou y a-t-il une autre façon de dessiner sur le fait sur mesure UIView
?
Voici le code pour générer le UIView
:
UIView* shapeView = [[UIView alloc]initWithFrame:CGRectMake(xOrigin,yOrigin+(i*MENU_BLOCK_FRAME_HEIGHT), self.shapeScroll.frame.size.width, MENU_BLOCK_FRAME_HEIGHT)];
shapeView.clipsToBounds = YES;
Et voici la fonction pour créer et retourner un UIBezierPath
:
- (UIBezierPath*)createPath
{
UIBezierPath* path = [[UIBezierPath alloc]init];
[path moveToPoint:CGPointMake(100.0, 50.0)];
[path addLineToPoint:CGPointMake(200.0,50.0)];
[path addLineToPoint:CGPointMake(200.0, 200.0)];
[path addLineToPoint:CGPointMake(100.0, 200.0)];
[path closePath];
return path;
}
Il n'y a pas si longtemps, je ne savais même pas comment prononcer Bézier, encore moins comment utiliser les chemins de Bézier pour créer une forme personnalisée. Ce qui suit est ce que j'ai appris. Il s'avère qu'ils ne sont pas aussi effrayants qu'ils le paraissent au début.
Ce sont les principales étapes:
drawRect
, soit à l'aide de CAShapeLayer
.Vous pouvez faire n'importe quoi, mais à titre d'exemple, j'ai choisi la forme ci-dessous. Il pourrait s'agir d'une touche contextuelle sur un clavier.
Examinez votre dessin de forme et divisez-le en éléments plus simples de lignes (pour les lignes droites), d'arcs (pour les cercles et les coins arrondis) et de courbes (pour toute autre chose).
Voici à quoi ressemblerait notre exemple de conception:
Nous allons commencer arbitrairement dans le coin inférieur gauche et travailler dans le sens des aiguilles d'une montre. Je vais utiliser la grille de l'image pour obtenir les valeurs x et y des points. Je vais tout codifier ici, mais bien sûr, vous ne feriez pas cela dans un vrai projet.
Le processus de base est:
UIBezierPath
moveToPoint
addLineToPoint
addArcWithCenter
addCurveToPoint
closePath
Voici le code pour faire le chemin dans l'image ci-dessus.
func createBezierPath() -> UIBezierPath {
// create a new path
let path = UIBezierPath()
// starting point for the path (bottom left)
path.move(to: CGPoint(x: 2, y: 26))
// *********************
// ***** Left side *****
// *********************
// segment 1: line
path.addLine(to: CGPoint(x: 2, y: 15))
// segment 2: curve
path.addCurve(to: CGPoint(x: 0, y: 12), // ending point
controlPoint1: CGPoint(x: 2, y: 14),
controlPoint2: CGPoint(x: 0, y: 14))
// segment 3: line
path.addLine(to: CGPoint(x: 0, y: 2))
// *********************
// ****** Top side *****
// *********************
// segment 4: arc
path.addArc(withCenter: CGPoint(x: 2, y: 2), // center point of circle
radius: 2, // this will make it meet our path line
startAngle: CGFloat(M_PI), // π radians = 180 degrees = straight left
endAngle: CGFloat(3*M_PI_2), // 3π/2 radians = 270 degrees = straight up
clockwise: true) // startAngle to endAngle goes in a clockwise direction
// segment 5: line
path.addLine(to: CGPoint(x: 8, y: 0))
// segment 6: arc
path.addArc(withCenter: CGPoint(x: 8, y: 2),
radius: 2,
startAngle: CGFloat(3*M_PI_2), // straight up
endAngle: CGFloat(0), // 0 radians = straight right
clockwise: true)
// *********************
// ***** Right side ****
// *********************
// segment 7: line
path.addLine(to: CGPoint(x: 10, y: 12))
// segment 8: curve
path.addCurve(to: CGPoint(x: 8, y: 15), // ending point
controlPoint1: CGPoint(x: 10, y: 14),
controlPoint2: CGPoint(x: 8, y: 14))
// segment 9: line
path.addLine(to: CGPoint(x: 8, y: 26))
// *********************
// **** Bottom side ****
// *********************
// segment 10: line
path.close() // draws the final line to close the path
return path
}
Remarque: Certains des codes ci-dessus peuvent être réduits en ajoutant une ligne et un arc dans une seule commande (car l'arc a un point de départ implicite). Voir ici pour plus de détails.
Nous pouvons dessiner le chemin soit dans une couche, soit dans drawRect
.
Méthode 1: Tracez un chemin dans une couche
Notre classe personnalisée ressemble à ceci. Nous ajoutons notre chemin Bézier à un nouveau CAShapeLayer
lorsque la vue est initialisée.
import UIKit
class MyCustomView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
func setup() {
// Create a CAShapeLayer
let shapeLayer = CAShapeLayer()
// The Bezier path that we made needs to be converted to
// a CGPath before it can be used on a layer.
shapeLayer.path = createBezierPath().cgPath
// apply other properties related to the path
shapeLayer.strokeColor = UIColor.blue.cgColor
shapeLayer.fillColor = UIColor.white.cgColor
shapeLayer.lineWidth = 1.0
shapeLayer.position = CGPoint(x: 10, y: 10)
// add the new layer to our custom view
self.layer.addSublayer(shapeLayer)
}
func createBezierPath() -> UIBezierPath {
// see previous code for creating the Bezier path
}
}
Et créer notre vue dans le contrôleur de vue comme ceci
override func viewDidLoad() {
super.viewDidLoad()
// create a new UIView and add it to the view controller
let myView = MyCustomView()
myView.frame = CGRect(x: 100, y: 100, width: 50, height: 50)
myView.backgroundColor = UIColor.yellow
view.addSubview(myView)
}
On a...
Hmm, c'est un peu petit parce que j'ai codé en dur tous les nombres. Je peux cependant redimensionner la taille du chemin, comme ceci:
let path = createBezierPath()
let scale = CGAffineTransform(scaleX: 2, y: 2)
path.apply(scale)
shapeLayer.path = path.cgPath
Méthode 2: Tracez le chemin dans draw
L'utilisation de draw
est plus lente que de dessiner sur le calque. Cette méthode n'est donc pas recommandée si vous n'en avez pas besoin.
Voici le code révisé pour notre vue personnalisée:
import UIKit
class MyCustomView: UIView {
override func draw(_ rect: CGRect) {
// create path (see previous code)
let path = createBezierPath()
// fill
let fillColor = UIColor.white
fillColor.setFill()
// stroke
path.lineWidth = 1.0
let strokeColor = UIColor.blue
strokeColor.setStroke()
// Move the path to a new location
path.apply(CGAffineTransform(translationX: 10, y: 10))
// fill and stroke the path (always do these last)
path.fill()
path.stroke()
}
func createBezierPath() -> UIBezierPath {
// see previous code for creating the Bezier path
}
}
ce qui nous donne le même résultat ...
Je vraiment recommande de regarder les documents suivants. Ce sont finalement ce qui a rendu les chemins de Bézier compréhensibles pour moi. (Et m'a appris à le prononcer:/bɛ zi ei /.)
Ce serait plus facile si vous utilisiez un CAShapeLayer
, comme ceci:
CAShapeLayer *shapeView = [[CAShapeLayer alloc] init];
Et définir sa path
:
[shapeView setPath:[self createPath].CGPath];
Enfin ajoutez-le:
[[self.view layer] addSublayer:shapeView];
Vous pouvez utiliser un CAShapeLayer
pour le faire.
Comme ça...
CAShapeLayer *shapeLayer = [CAShapeLayer layer];
shapeLayer.path = [self createPath].CGPath;
shapeLayer.strokeColor = [UIColor redColor].CGColor; //etc...
shapeLayer.lineWidth = 2.0; //etc...
shapeLayer.position = CGPointMake(100, 100); //etc...
[self.layer addSublayer:shapeLayer];
Cela va ensuite ajouter et dessiner le chemin sans avoir à remplacer drawRect
.
Il y a plusieurs façons d'accomplir ce que vous souhaitez. Ceux que j'ai le plus souvent rencontrés sont: remplacez drawRect, dessinez votre forme dans un CAShapeLayer , puis ajoutez-la en tant que sous-couche à votre vue, ou tracez votre chemin dans un autre contexte , enregistrez-le en tant qu’image, puis ajoutez-le à votre vue.
Tous ces choix sont raisonnables, et celui qui convient le mieux dépend de nombreux autres facteurs, tels que l'ajout continu de formes, la fréquence d'appellation, etc.
Comme les autres affiches l'ont souligné, l'utilisation d'un calque de forme est un bon choix.
Les couches de forme a sont susceptibles de vous offrir de meilleures performances que de remplacer drawRect.
Si vous voulez dessiner vous-même votre chemin, alors oui, vous devez remplacer drawRect pour votre classe de vue personnalisée.
Oui, vous devez écraser le drawrect si vous voulez dessiner quelque chose.Créer un UIBezierPath peut être fait n’importe où, mais pour dessiner quelque chose, vous devez le faire dans la méthode drawrect
Vous devriez appeler setNeedsDisplay
si vous écrasez drawRect dans une sous-classe de UIView, qui est essentiellement une vue personnalisée qui dessine quelque chose à l'écran, telle que des lignes, une image, un rectangle.