iOS dev > Learn-how to draw 1-pixel lines correctly

Source: Internet
Author: User
Tags uikit

First, point Vs Pixel

In iOS, when we use frames such as quartz,uikit,coreanimation, all coordinate systems are measured by point. The system will help us deal with point-to-pixel conversions when actually rendering to settings.

The benefits of doing so isolate the change, i.e. we do not need to focus on whether the current device is retina after the layout, and can be laid out directly in a set of coordinate systems.

In practice we need to keep this in mind:

One point does isn't necessarily correspond to one physical pixel.

A line of 1 point on a non-retina screen is a pixel, which may be 2 or 3 on the Retina screen, depending on the DPI of the system device.

On iOS systems, the Uiscreen,uiview,uiimage,calayer class provides properties to get the scale factor.

Native rendering techniques naturally help us with scale factor, for example, in the DrawRect: method, Uikit automatically sets the tangent scale factor based on the currently running device. So the drawrect: anything drawn in the method will be automatically scaled to the physical screen of the device.

Based on the above information, we can see that we do not need to pay attention to pixel in most cases, but some cases need to consider the conversion of pixels.

For example, draw a 1-pixel split Line

The first idea you'll see is that you can calculate the point of a 1-pixel line directly based on the zoom factor of the current screen, and then set the line width.

The code is as follows:

1.0f/[UIScreen Mainscreen].scale

On the surface it looks normal, but with the actual device testing you will find that the rendered line width is not 1 pixels.

Why?

For good visuals, the drawing system usually uses a technique called antialiasing (anti-aliasing), and iOS is no exception.

The display screen has a lot of small display units, which can be understood as a single unit that represents a pixel. If you want to draw a black line, the lines just fall in a column or a row of display cells, will render a standard one pixel black line.

But if the line falls in the middle of two rows or columns, you get a "distorted" line, which is actually two pixels wide gray line.

As shown in the following:

Positions defined by whole-numbered points fall at the midpoint between pixels. For example, if you draw a one-pixel-wide vertical line from (1.0, 1.0) to (1.0, 10.0), you get a fuzzy-grey line. If you draw a two-pixel-wide line, you get a solid black line because it fully covers and pixels (one on either side of th e specified point). As a rule, lines that is a odd number of physical pixels wide appear softer than lines with widths measured in even numb ers of physical pixels unless you adjust their position to make them cover pixels fully.

As an official explanation, simply translate:

Rule: An odd pixel width line will appear as a soft width extension to an upward integer width line at render time, unless you manually adjust the position of the line so that the line falls exactly within the row or column of the display unit.

How to align it?

On a low-resolution display (with a scale factor of 1.0), a one-point-wide line is one pixel wide. To avoid antialiasing when you draw a one-point-wide horizontal or vertical line, if the line was an odd number of pixels I n width, you must offset the position by 0.5 points to either side of a whole-numbered position. If the line was an even number of points in width, to avoid a fuzzy line, you are must not doing so.

On a-high-resolution display (with a scale factor of 2.0), a-line-is-one point wide are not-antialiased at all because It occupies the pixels (from-0.5 to +0.5). To draw a line this covers only a single physical pixel, you would need to make it 0.5 points in thickness and offset it Position by 0.25 points. A comparison between the types of screens is shown in Figure 1-4.

Translate a bit

On a non-HD screen, a point corresponds to one pixel. To prevent distortion in the odd-pixel line rendering caused by "antialiasing", you need to set the offset 0.5 point.

On the HD screen, to draw a line of pixels, you need to set the line width to 0.5 point, and the colleague set offset to 0.25 point.

If the line width is even point, do not set the offset, or the line will be distorted.

As shown in the following:

Read the above explanation, we understand the 1 pixel wide line distortion reasons, and solutions.

So the problem seems to have been solved? Think about why the position value is different on the non-retina and retina screens, the former is 0.5Point and the latter is 0.25Point, so how much is the 6 Plus device with scale 3?

To answer this question, we need to understand the principle of how much adjustment remains.

Looking back at the picture above, each of the squares in the picture represents a pixel, and the top tag is the coordinates of the code we are laying out.

You can see the non-Retina screen on the left, we want to draw a vertical line at this position (3,0), because the smallest unit of the rendering is pixels, and (3,0) This coordinate is located in the middle of two pixels, the system will be around the coordinates 3 of the two columns of pixels to fill, in order not to appear too wide, Fades the color of the line. So, based on the above information, we can conclude that if you want to draw a line with a wide pixel width, you have to move the plotted coordinates to (2.5, 0) or (3.5,0) This position, so that the system renders exactly one column of pixels, which is the standard one-pixel line.

Based on the above analysis, we can draw a "scale of 3 6 Plus" device if you want to draw 1 pixel-wide lines, the position adjustment should also be 0.5 pixels, the point should be calculated as follows:

(1.0f/[UIScreen Mainscreen].scale)/2;

A macro that draws a pixel line:

#define SINGLE_LINE_WIDTH (1/[UIScreen Mainscreen].scale)

#define SINGLE_LINE_ADJUST_OFFSET ((1/[UIScreen Mainscreen].scale)/2)

Use the following code:

CGFloat XPos = 5;

UIView *view = [[UIView alloc] Initwithframe:cgrect (x-single_line_adjust_offset, 0, Single_line_width, 100)];

Second, the correct drawing grid lines

Paste the code of the GridView, which offsets the odd pixels of the grid lines to prevent the blurring of lines.

SvGridView.h

//

SvGridView.h

Svsinglepixel

//

Created by Xiaoyong.cxy on 6/23/15.

Copyright (c) smileevday. All rights reserved.

//

#import @interface Svgridview:uiview

/**

* @brief grid spacing, default 30

*/

@property (nonatomic, assign) CGFloat gridspacing;

/**

* @brief grid line width, default is 1 pixel (1.0f/[UIScreen Mainscreen].scale)

*/

@property (nonatomic, assign) CGFloat gridlinewidth;

/**

* @brief grid color, default blue

*/

@property (nonatomic, strong) Uicolor *gridcolor;

@end

svgridview.m

//

svgridview.m

Svsinglepixel

//

Created by Xiaoyong.cxy on 6/23/15.

Copyright (c) smileevday. All rights reserved.

//

#import "SvGridView.h"

#define SINGLE_LINE_WIDTH (1/[UIScreen Mainscreen].scale)

#define SINGLE_LINE_ADJUST_OFFSET ((1/[UIScreen Mainscreen].scale)/2)

@implementation Svgridview

@synthesize gridcolor = _gridcolor;

@synthesize gridspacing = _gridspacing;

-(Instancetype) initWithFrame: (CGRect) frame

{

self = [super Initwithframe:frame];

if (self) {

Self.backgroundcolor = [Uicolor Clearcolor];

_gridcolor = [Uicolor Bluecolor];

_gridlinewidth = Single_line_width;

_gridspacing = 30;

}

return self;

}

-(void) Setgridcolor: (Uicolor *) Gridcolor

{

_gridcolor = Gridcolor;

[Self setneedsdisplay];

}

-(void) setgridspacing: (cgfloat) gridspacing

{

_gridspacing = gridspacing;

[Self setneedsdisplay];

}

-(void) Setgridlinewidth: (cgfloat) Gridlinewidth

{

_gridlinewidth = Gridlinewidth;

[Self setneedsdisplay];

}

Only override Drawrect:if perform custom drawing.

An empty implementation adversely affects performance during animation.

-(void) DrawRect: (cgrect) rect

{

Cgcontextref context = Uigraphicsgetcurrentcontext ();

Cgcontextbeginpath (context);

CGFloat linemargin = self.gridspacing;

/**

* https://developer.apple.com/library/ios/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/ Graphicsdrawingoverview/graphicsdrawingoverview.html

* The drawing position needs to be adjusted only if the line width you want to draw is an odd pixel

*/

CGFloat pixeladjustoffset = 0;

if (((int) (Self.gridlinewidth * [UIScreen Mainscreen].scale) + 1)% 2 = = 0) {

Pixeladjustoffset = Single_line_adjust_offset;

}

CGFloat xPos = Linemargin-pixeladjustoffset;

CGFloat yPos = Linemargin-pixeladjustoffset;

while (XPos < self.bounds.size.width) {

Cgcontextmovetopoint (context, XPos, 0);

Cgcontextaddlinetopoint (context, XPos, self.bounds.size.height);

XPos + = Linemargin;

}

while (YPos < self.bounds.size.height) {

Cgcontextmovetopoint (context, 0, YPos);

Cgcontextaddlinetopoint (context, self.bounds.size.width, YPos);

YPos + = Linemargin;

}

Cgcontextsetlinewidth (context, self.gridlinewidth);

Cgcontextsetstrokecolorwithcolor (context, self.gridColor.CGColor);

Cgcontextstrokepath (context);

}

@end

Here's how to use it:

Svgridview *gridview = [[Svgridview alloc] initWithFrame:self.view.bounds];

Gridview.autoresizingmask = Uiviewautoresizingflexiblewidth | Uiviewautoresizingflexibleheight;

Gridview.alpha = 0.6;

Gridview.gridcolor = [Uicolor Greencolor];

[Self.view Addsubview:gridview];

A city problems

All right, here we go. The whole knowledge of this article is over, and finally I have a question.

Why does the designer have to have a pixel line?

A pixel line may look appropriate on a non-retina device, and the display on the Retina screen may be thinner. is not sure to need a pixel line, it needs to be handled according to the situation.

Reference Documentation:

https://developer.apple.com/library/ios/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/ Graphicsdrawingoverview/graphicsdrawingoverview.html

Note: Smileevday reserves all rights to this article

Source: Smileevday

iOS dev > Learn-how to draw 1-pixel lines correctly

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.