2017-03-10 2 views
3

J'utilise un CAShapeLayer avec un UIBezierPath pour dessiner un cadre encadré dans une vue.CAShapeLayer pixel manquant dans le coin supérieur gauche

Cela fonctionne très bien, mais le tout premier pixel (haut, gauche) n'est pas dessiné.

Ceci est mon code:

let focusSize = CGRect(x: focusX, y: focusY, width: focusWidth, height: focusHeight) 
let focusPath = UIBezierPath(roundedRect: focusSize, cornerRadius: 0) 

let borderLayer = CAShapeLayer() 
borderLayer.path = focusPath.cgPath 
borderLayer.fillColor = UIColor.clear.cgColor 
borderLayer.strokeColor = UIColor.white.cgColor 
borderLayer.lineWidth = 2 
borderLayer.frame = self.someView.bounds 
self.someView.layer.addSublayer(borderLayer) 

Le résultat (note du pixel dans le coin supérieur gauche):

Weird pixel

Je pensais que cela pourrait être lié à l'anticrénelage, mais en jouant autour avec le x, y et borderWidth ne semble pas résoudre le problème. Est-ce que quelqu'un sait ce qui cause cela?

+0

Avez-vous essayé d'apporter votre couche à l'avant? Avez-vous essayé d'imprimer toutes les sous-couches de votre 'someView'? –

Répondre

5

Pour une raison quelconque, lorsque vous créez un chemin à l'aide de (roundedRect rect: CGRect, cornerRadius: CGFloat), il n'est pas fermé (en dépit de ce qui est indiqué dans la documentation).

L'appel focusPath.close() ferme le chemin et supprime le pixel manquant. Toutefois, si vous ne voulez pas de coins arrondis, utilisez simplement un rect normal et il dessine correctement.

let focusPath = UIBezierPath(rect: focusSize)

Pour les personnes intéressées ici sont les chemins résultants:

UIBezierPath(roundedRect: CGRect(x: 10, y: 10, width: 100, height: 100), cornerRadius: 0) 
<UIBezierPath: 0x6180000b8000; <MoveTo {10, 10}>, 
<LineTo {110, 10}>, 
<LineTo {110, 110}>, 
<LineTo {10, 110}>, 
<LineTo {10, 10}>, 
<LineTo {10, 10}> 

//After calling path.close() 
<UIBezierPath: 0x6180000b8000; <MoveTo {10, 10}>, 
<LineTo {110, 10}>, 
<LineTo {110, 110}>, 
<LineTo {10, 110}>, 
<LineTo {10, 10}>, 
<LineTo {10, 10}>, 
<Close> 

UIBezierPath(rect: CGRect(x: 10, y: 10, width: 100, height: 100)) 
<UIBezierPath: 0x6180000b7f40; <MoveTo {10, 10}>, 
<LineTo {110, 10}>, 
<LineTo {110, 110}>, 
<LineTo {10, 110}>, 
<Close> 

Réglage de la lineCap peut faire correctement apparaître la boîte, mais ne fixe pas la question car il étend simplement les points d'extrémité visibles et couvre le peu manquant. Définissez borderLayer.lineJoin = kCALineJoinBevel pour voir pourquoi cela peut poser un problème.

+0

Il devrait se traduire par un rectangle selon la documentation de la pomme: https://developer.apple.com/reference/uikit/uibezierpath/1624356-init –

+0

Il devrait, mais ce n'est pas le cas. Essayez-le. –

+0

Pour les personnes qui votent cette réponse; Essayez-le d'abord! C'est correct – Brett

2

La raison pour laquelle vous voyez un pixel manquant sur votre rect est que vous n'avez pas configuré la propriété lineCap correctement.

Essayez d'ajouter cette ligne:

borderLayer.lineCap = kCALineCapSquare 

Pour en savoir plus sur le cap de la ligne (et ligne de jonction qui est également important de comprendre) voir cette page: http://calayer.com/core-animation/2016/05/22/cashapelayer-in-depth.html#line-cap

+0

Ceci montre clairement la frontière correctement, mais si la méthode roundedRect a créé un chemin fermé comme cela est supposé le lineCap n'aurait aucun effet. –

+1

Vous avez raison. J'ai presque suggéré d'utiliser 'close()' sur le chemin mais j'ai alors vu que la documentation disait que le chemin était fermé. Je l'ai trouvé bizarre et je l'ai suggéré à la place. La documentation est fausse, c'est la vraie réponse ... – deadbeef

2

Oui selon le document, il devrait être un rect mais je ne pense pas qu'il mentionne le lineWidth

Cela semble être la raison pour laquelle vous voyez un pixel manquant

borderLayer.lineWidth = 2 

Maintenant, lorsque vous modifiez la largeur de 1, alors il dessine un rectangle parfait sans pixels manquants

Modification du lineWidth à 10 montre des différences considérables dans l'écart

La solution à votre problème serait d'utiliser cette

borderLayer.lineCap = kCALineCapSquare 

Vérifier ces lineCap & Line Cap Values

+0

C'est intéressant, je ne m'attendrais pas à ce que le rayon de la bordure soit tracé si la valeur est à 0. – Rob