iPhone Core Graphics thicker dashed line for subvi

2019-04-23 17:47发布

问题:

I have a UIView and within it I've drawn a line using Core Graphics by overriding drawRect. This view also contains one subview which also draws a line. However, whilst both views are using pretty much the same code (for testing purposes at least), the lines drawn on them do not appear the same:

As you can see - the dashed line at the top is noticeably thicker than the bottom one and I have no idea why. Below is the code used by the two UIViews in their drawRect methods. If you have any idea why this is happening then I'd appreciate your help and advice!

First View:

CGContextRef context = UIGraphicsGetCurrentContext();

CGContextSetStrokeColorWithColor(context, [[UIColor whiteColor] CGColor]);

CGFloat dashes[] = {1,1};

CGContextSetLineDash(context, 0.0, dashes, 2);
CGContextSetLineWidth(context, 0.6);

CGContextMoveToPoint(context, CGRectGetMinX(rect), CGRectGetMaxY(rect));
CGContextAddLineToPoint(context, CGRectGetMaxX(rect), CGRectGetMaxY(rect));

CGContextStrokePath(context);

SubUIView *view = [[SubUIView alloc] initWithFrame:rect];
[self addSubview:view];
[view release];

The view is definitely only being drawn once. I appreciate drawRect may not be the best place for adding a subview but the problem remains even with it added in the main initWithFrame method.

Second View:

CGContextRef context = UIGraphicsGetCurrentContext();

CGContextSetStrokeColorWithColor(context, [[UIColor whiteColor] CGColor]);

CGFloat dashes[] = {1,1};

CGContextSetLineDash(context, 0.0, dashes, 2);
CGContextSetLineWidth(context, 0.6);

CGContextMoveToPoint(context, CGRectGetMinX(rect), CGRectGetMidY(rect));
CGContextAddLineToPoint(context, CGRectGetMaxX(rect), CGRectGetMidY(rect));

CGContextStrokePath(context);

回答1:

It could be a result of anti-aliasing if your rect does not fall on integers. You can disable anti-aliasing with CGContextSetShouldAntialias( context, NO ). I think there's also a function for making a rect integral, but I can't remember what it is.



回答2:

First, you should fix the problem of the drawing code being WET*. You say you're doing this “for testing purposes”, but this actually makes testing harder, since you have to change both pieces of code and/or keep straight which version you're working on. The worst case is when you change both pieces of code in different ways and have to merge them by hand.

I'd say move the dashed-line code to the subview, add properties for anything the two pieces of code need to do differently, and create two subviews (and not in drawRect:—seriously).

As for the actual problem: Well, I don't see a big image, I see a tiny image, and I can only guess that the greater boldness of the upper line than that of the lower line means that the upper line is thicker.

By the way, the rect is not necessarily the bounds of your image. Don't ever assume that it is, or you will get funky drawing when it isn't. Assume that it some section of the bounds—possibly, but possibly not, the whole thing. When you mean [self bounds], say [self bounds].

The problem is most likely the difference between CGRectGetMidY([self bounds]) and CGRectGetMaxY([self bounds]). One includes a fraction that splits a pixel, whereas the other is a multiple of one pixel or close to it. (Not necessarily a multiple of 1—on a Retina Display, 1 pt = 2 pixels, so 1 pixel = 0.5 pt.) Try flooring both numbers and optionally adding 0.5, and see which way you like better.

There's no way to make it work out perfectly with a 0.6-pt line width. There is simply no whole number of pixels that works out to. All you can do is work out what looks best and do that.

*Written Elsewhere Too, the opposite of DRY.