UIBezierPath trait 1px ligne et remplir 1px largeur rectangle – résultats différents.

Voici un dessin simple

- (void)drawRect:(CGRect)rect { //vertical line with 1 px stroking UIBezierPath *vertLine = [[UIBezierPath alloc] init]; [vertLine moveToPoint:CGPointMake(20.0, 10.0)]; [vertLine addLineToPoint:CGPointMake(20.0, 400.0)]; vertLine.lineWidth = 1.0; [[UIColor blackColor] setStroke]; [vertLine stroke]; //vertical rectangle 1px width UIBezierPath *vertRect= [UIBezierPath bezierPathWithRect:CGRectMake(40.0, 10.0, 1.0, 390.0)]; [[UIColor blackColor] setFill]; [vertRect fill]; } 

Sur la rétine 3GS et le simulateur, la première ligne est floue et semble plus large que 1 px, mais la deuxième ligne est nette.

Malheureusement je n'ai ni iPhone4 ni le nouvel iPad à tester, mais sur simulateur de rétine les deux lignes se ressemblent.

Question: Est-ce que le rectangle au lieu du trait est le seul moyen d'get le même résultat pour les appareils autres que la rétine et la rétine?

Vous remplissez l'intérieur du rectangle mais vous caressez la ligne depuis le centre. Puisque les coordonnées dans les deux cas (les coins du rectangle et les coordonnées de début et de fin dans la ligne) sont définies comme des valeurs de nombres entiers (aucune fraction), les coordonnées se trouvent sur des limites de points exactes.

J'ai dit "coordonnées" ci-dessus en parlant des points de la ligne, pour ne pas les confondre avec les points sur l'écran. J'ai également dit "limites de points" au lieu de "limites de pixels" pour la même raison. iOS définit ses coordonnées et tous les points dans ce qu'on appelle des "points" au lieu de pixels. Un point est une mesure indépendante de la résolution. Les dispositifs rétiniens et non rétiniens ont tous deux le même nombre de points sur l'écran, c'est juste qu'ils correspondent à un nombre différent de pixels réels.

Examinons une ligne qui se trouve sur les limites du point (comme dans votre question) par rapport à remplir un rectangle où les coins se trouvent sur les limites du point:

Dans les illustrations ci-dessous, je caresse une ligne avec du noir et remplis un rectangle d'orange à la fois sur un écran sans rétine et sur un écran rétine. J'ai aussi dessiné la ligne et le rectangle en bleu. Dans les deux cas, vous pouvez voir la taille d'un point pour cette résolution et la comparer à la grid de pixels réelle.

Dans le cas non-rétine, vous pouvez voir que le fait d'essayer de couper la ligne du centre avec une ligne de 1 point (dans ce cas correspondant à une largeur de 1 pixel) remplirait la moitié des pixels en haut et la moitié des pixels au dessous de. Comme les pixels ne sont qu'à moitié remplis, l'opacité de ces pixels est de 50%. Cela entraîne la couleur plus claire (sur un fond blanc). Puisque les deux pixels en haut et en bas sont remplis, le fait de caresser les deux remplit à la fois les pixels en haut et en bas. Cela donne à la ligne l'apparence d'une largeur de 2 pixels au lieu d'une.

Vous pouvez rapidement comparer cela au rectangle qui est rempli à l'intérieur.

non rétine

Le même cas sur un écran rétine semble différent. Dans ce cas, la taille d'un point est la même mais il est composé de 4 pixels au lieu de 1. Cette fois, en plaçant la ligne, un demi-point au dessus de la ligne et un demi-point sous la ligne rempliront complètement la ligne de pixels ci-dessus et ci-dessous en raison de l'écran de plus haute résolution. Cela signifie que la ligne semble avoir 1 sharepoint large et que la couleur semble complètement opaque.

Nous pouvons également voir que le rectangle rempli est le même.

rétine


Pour résoudre ce problème, vous devez placer les points de votre ligne sur les demi-pixels. Caresser la ligne depuis le centre sur un dispositif de basse résolution signifie que la ligne s'étend d'un demi-point vers le haut et d'un demi-point vers le bas. Comme le centre de la ligne se trouve maintenant au centre du point, cela signifie que la ligne contournée se trouve entièrement à l'intérieur des pixels et que la ligne semble nette. Faire cela n'aura aucun effet sur la ligne de la rétine puisque descendre (ou augmenter) d'un demi-point signifie toujours que vous remplissez entièrement les pixels au-dessus et au-dessous.

Dans l'illustration ci-dessous (pour la rétine), j'ai montré à la fois la grid de points et la grid de pixels.

demi-pixel non-rétinedemi-pixel rétine

La raison pour laquelle vous obtenez des résultats différents avec AVC et remplissage est que leurs interprétations des arguments sont différentes.

Le trait ajoute la moitié de la largeur de la ligne de chaque côté de la coordonnée. Donc, votre point est 20.0 et la largeur de la ligne est 1px. Le résultat sera une ligne noire de 1 pixel entre (19.5-20.5), théoriquement. Comme il n'y a pas de pixel non embedded sur l'écran de l'appareil, il sera converti en pixels gris / ligne floue entre (19-21). Pour contourner cela, vous devez additionner chacune de vos coordonnées avec 0.5 (comme dans CGPointMake (20.5, 10.5)) afin que la largeur ne soit plus divisée entre les pixels.

Cependant, les arguments dans le remplissage sont utilisés pour définir les limites de la région à remplir, CGRectMake (40.0, 10.0, 1.0, 390.0) implique une région entre (40 – 41). En conséquence, aucune partie fractionnaire ne tombe sur les pixels pour paraître floue.