How iOS correctly draws 1-pixel lines

Source: Internet
Author: User
Tags uikit
<span id="Label3"></p>first, Point Vs Pixel<p><p>In ios, when we use frames such as quartz,uikit,coreanimation, all coordinate systems are measured by point. The system will help us handle the conversion of point to pixel when actually rendering to the Device.<br>The benefits of this isolation change, that is, we do not need to focus on the layout of the current device is retina, directly according to a set of coordinate system to Layout.</p></p><p><p>In practice we need to keep this in mind:</p></p><pre><pre><code class="hljs applescript"><span class="hljs-keyword">does <span class="hljs-keyword">not necessarily correspond <span class="hljs-keyword">to one physical pixel.</span></span></span></code></pre></pre><p><p>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.</p></p><p><p>On iOS systems, the Uiscreen,uiview,uiimage,calayer class provides properties to get the scale Factor.<br>Native rendering techniques naturally help us with scale factor, for example, in the drawrect: method, Uikit automatically sets the correct 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.</p></p><p><p>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.</p></p><pre><pre><code class="hljs">例如画1个像素的分割线</code></pre></pre><p><p>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.<br>The code is as Follows:</p></p><pre><pre><code class="hljs cpp"><span class="hljs-number">1.0f / [UIScreen mainScreen].scale</span></code></pre></pre><p><p>On the surface it looks normal, but with the actual device testing you will find that the rendered line width is not 1 pixels.</p></p> <blockquote> <blockquote> <p>why?</p> </blockquote> </blockquote><p><p>For good visuals, the drawing system usually uses a technique called antialiasing (anti-aliasing), and iOS is no Exception.<br>The display screen consists of a number of small display units, which can be simply understood as a single cell representing a pixel. If you want to draw a black line that falls exactly within a column or a line of display cells, it will render a standard one-pixel black Thread.<br>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.</p></p><p><p>As shown in the Following:</p></p><p><p></p></p><pre><code class="hljs livecodeserver">Positions defined<span class="hljs-keyword">By<span class="hljs-keyword">Whole-numbered points Fall<span class="hljs-keyword">At<span class="hljs-operator">The midpoint between Pixels. For example,<span class="hljs-keyword">If you draw<span class="hljs-operator">A<span class="hljs-constant">One-pixel-wide Vertical<span class="hljs-built_in">Line<span class="hljs-built_in">From (<span class="hljs-number">1.0,<span class="hljs-number">1.0)<span class="hljs-built_in">to (<span class="hljs-number">1.0,<span class="hljs-number">10.0), You<span class="hljs-built_in">Get<span class="hljs-operator">A fuzzy grey<span class="hljs-built_in">Line. If you draw<span class="hljs-operator">A<span class="hljs-constant">Two-pixel-wide<span class="hljs-built_in">line, You<span class="hljs-built_in">Get<span class="hljs-operator">A solid<span class="hljs-keyword">Black<span class="hljs-built_in">Line because<span class="hljs-keyword">It fully covers<span class="hljs-constant">Pixels (<span class="hljs-constant">One<span class="hljs-command"><span class="hljs-keyword">On<span class="hljs-title">Either<span class="hljs-title">Side<span class="hljs-title">Of<span class="hljs-title">The<span class="hljs-title">Specified<span class="hljs-title">Point).<span class="hljs-title">As<span class="hljs-title">A<span class="hljs-title">Rule<span class="hljs-title">Lines<span class="hljs-title">That<span class="hljs-title">Is<span class="hljs-title">An<span class="hljs-title">Odd<span class="hljs-title">Number<span class="hljs-title">Of<span class="hljs-title">Physical<span class="hljs-title"><span class="hljs-title">pixels <span class="hljs-title">wide <span class="hljs-title">appear <span class="hljs-title">softer <span class="hljs-title">than <span class="hljs-title">lines <span class="hljs-title">with <span class="hljs-title">widths <span class="hljs-title">measured <span class="hljs-title">in <span class="hljs-title">even <span class="hljs-title">numbers <span class="hljs-title">of <span class="hljs-title">physical <span class="hljs-title">pixels <span class="hljs-title">unless <span class="hljs-title">you <span class="hljs-title">adjust <span class="hljs-title">their <span class="hljs-title">position <span class="hljs-title">to <span class="hljs-title">make <span class="hljs-title">them <span class="hljs-title">cover <span class="hljs-title">pixels <span class="hljs-title">fully. </span> </span> </span> </span> </span> </span> </span> </span> </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span> </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre><p><p>As an official explanation, simply Translate:</p></p><pre><pre><code class="hljs">规定:奇数像素宽度的线在渲染的时候将会表现为柔和的宽度扩展到向上的整数宽度的线,除非你手动的调整线的位置,使线刚好落在一行或列的显示单元内。</code></pre></pre><p><p>How to Align it?</p></p><pre><code class="hljs livecodeserver">On<span class="hljs-operator">A low-resolution display (<span class="hljs-operator">With<span class="hljs-operator">A scale factor<span class="hljs-operator">Of<span class="hljs-number">1.0),<span class="hljs-operator">A<span class="hljs-constant">One-point-wide<span class="hljs-built_in">Line is<span class="hljs-constant">One pixel Wide. To avoid antialiasing when you draw<span class="hljs-operator">A<span class="hljs-constant">One-point-wide Horizontal<span class="hljs-operator">or vertical<span class="hljs-built_in">Line<span class="hljs-keyword">If<span class="hljs-operator">The<span class="hljs-built_in">Line is<span class="hljs-operator">An odd<span class="hljs-built_in">Number<span class="hljs-operator">of pixels<span class="hljs-operator">In width, you must<span class="hljs-built_in">Offset<span class="hljs-operator">The position<span class="hljs-keyword">By<span class="hljs-number">0.5 points<span class="hljs-built_in">to either side<span class="hljs-operator">Of<span class="hljs-operator">A<span class="hljs-keyword">Whole-numbered Position. If<span class="hljs-operator">The<span class="hljs-built_in">Line is<span class="hljs-operator">An even<span class="hljs-built_in">Number<span class="hljs-operator">of points<span class="hljs-operator">In width,<span class="hljs-built_in">To avoid<span class="hljs-operator">A fuzzy<span class="hljs-built_in">line, must<span class="hljs-operator">Not<span class="hljs-built_in">Do So. On<span class="hljs-operator">A high-resolution display (<span class="hljs-operator">With<span class="hljs-operator">A scale factor<span class="hljs-operator">Of<span class="hljs-number">2.0),<span class="hljs-operator">A<span class="hljs-built_in">Line<span class="hljs-constant">One point wide is<span class="hljs-operator">Not antialiased<span class="hljs-keyword">At all because<span class="hljs-keyword">It occupies<span class="hljs-constant">Pixels (<span class="hljs-built_in">from <span class="hljs-built_in">-<span class="hljs-number">0.5 to <span class="hljs-built_in">+<span class="hljs-number">0.5). To draw <span class="hljs-operator">a line This <span class="hljs-built_in">covers only <span class="hljs-operator">a single physical pixel would need to make <span class="hljs-built_in"> <span class="hljs-keyword">it <span class="hljs-number">0.5 points <c10> in thickness <span class="hljs-operator">and <span class="hljs-built_in">offset its position <span class="hljs-keyword">by <span class="hljs-number">0.25 Points. A comparison between the types of screens is shown in Figure <span class="hljs-operator"> <span class="hljs-constant"> <span class="hljs-operator"> <span class="hljs-operator"> <span class="hljs-number">1-<span class="hljs-number">4.</span> </span> </span> </span></span></span></span></span></span></span> </c10></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre><p><p>Translate a bit</p></p><pre><pre><code class="hljs mathematica">在非高清屏上,一个<span class="hljs-keyword">Point对应一个像素。为了防止“antialiasing”导致的奇数像素的线渲染时出现失真,你需要设置偏移<span class="hljs-number">0.5 <span class="hljs-keyword">Point。在高清屏幕上,要绘制一个像素的线,需要设置线宽为<span class="hljs-number">0.5个<span class="hljs-keyword">Point,同事设置偏移为<span class="hljs-number">0.25 <span class="hljs-keyword">Point。如果线宽为偶数<span class="hljs-keyword">Point的话,则不要去设置偏移,否则线条也会失真。</span></span></span></span></span></span></span></span></code></pre></pre><p><p>As shown in the Following:</p></p><p><p></p></p><p><p>Read the above explanation, we understand the 1 pixel wide line distortion reasons, and Solutions.<br>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?<br>To answer this question, we need to understand how much adjustment depends on the Principle.</p></p><p><p></p></p><p><p>Looking back at the picture above, each of the squares in the picture represents a pixel, and the top tag represents the coordinates of our Layout.<br>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.</p></p><p><p>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:</p></p><pre><pre><code class="hljs scheme"><span class="hljs-list">(<span class="hljs-keyword">1.0f / <span class="hljs-list">[<span class="hljs-keyword">UIScreen mainScreen].scale) / <span class="hljs-number">2<span class="hljs-comment">;</span></span></span></span></span></span></code></pre></pre><p><p>A macro that draws a pixel line:</p></p><pre><pre><code class="hljs stylus"><span class="hljs-hexcolor">#define SINGLE_LINE_WIDTH (<span class="hljs-number">1 / [UIScreen mainScreen].scale)<span class="hljs-hexcolor">#define SINGLE_LINE_ADJUST_OFFSET ((<span class="hljs-number">1 / [UIScreen mainScreen].scale) / <span class="hljs-number">2)</span></span></span></span></span></code></pre></pre><p><p>Use the following code:</p></p><pre><pre><code class="hljs objectivec"><span class="hljs-built_in">CGFloat xPos = <span class="hljs-number">5;<span class="hljs-built_in">UIView *view = [[<span class="hljs-built_in">UIView alloc] initWithFrame:<span class="hljs-built_in">CGrect(x - SINGLE_LINE_ADJUST_OFFSET, <span class="hljs-number">0, SINGLE_LINE_WIDTH, <span class="hljs-number">100)];</span></span></span></span></span></span></span></code></pre></pre><p><p></p></p>second, the correct drawing grid lines<p><p>Paste the code of the gridview, which offsets the odd pixels of the grid lines to prevent the blurring of lines.</p></p><p><p>SvGridView.h</p></p><pre><code class="hljs objectivec"><span class="hljs-comment">//<span class="hljs-comment">SvGridView.h<span class="hljs-comment">Svsinglepixel<span class="hljs-comment">//<span class="hljs-comment">Created by Xiaoyong.cxy on 6/23/15.<span class="hljs-comment">Copyright (c) Smileevday. All Rights Reserved.<span class="hljs-comment">//<span class="hljs-preprocessor">#import<span class="hljs-title"><UIKit/UIKit.h><span class="hljs-class"><span class="hljs-class"><span class="hljs-keyword"> @interface <span class="hljs-title">svgridview: <span class=" Hljs-title ">uiview<span class=" hljs-comment ">/** * @brief grid spacing, default to */<span class=" hljs-keyword "> @property (<span class="hljs-keyword">nonatomic, <span class="hljs-keyword">assign) <span class="hljs-built_in">CGFloat gridspacing; <span class="hljs-comment">/** * @brief grid line width, default 1 pixel (1.0f/[uiscreen mainscreen].scale) */<span class=" Hljs-keyword "> @property (<span class=" hljs-keyword ">nonatomic, <span class=" hljs-keyword ">assign) <span class=" Hljs-built_in ">cgfloat gridlinewidth; <span class="hljs-comment">/** * @brief grid color, default Blue */<span class="hljs-keyword"> @property ( <span class="hljs-keyword">nonatomic, <span class="hljs-keyword">strong) <span class="hljs-built_in">UIColor * gridcolor; <span class="hljs-keyword"> @end </span> </span> </span> </span> </span> </span> </span> </span> </span> </span> </span> </span> </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre><p><p>svgridview.m</p></p><pre><code class="hljs objectivec"><span class="hljs-comment">//<span class="hljs-comment">svgridview.m<span class="hljs-comment">Svsinglepixel<span class="hljs-comment">//<span class="hljs-comment">Created by Xiaoyong.cxy on 6/23/15.<span class="hljs-comment">Copyright (c) Smileevday. All Rights Reserved.<span class="hljs-comment">//<span class="hljs-preprocessor">#import<span class="hljs-title">"SvGridView.h"<span class="hljs-preprocessor">#define Single_line_width (1/[uiscreen Mainscreen].scale)<span class="hljs-preprocessor">#define Single_line_adjust_offset ((1/[uiscreen Mainscreen].scale)/2)<span class="hljs-class"><span class="hljs-keyword">@implementation<span class="hljs-title">Svgridview<span class="hljs-keyword">@synthesize Gridcolor = _gridcolor;<span class="hljs-keyword">@synthesize gridspacing = _gridspacing;-(instancetype) initwithframe: (<span class="hljs-built_in">Cgrect) frame{<span class="hljs-keyword">Self = [<span class="hljs-keyword">Super initwithframe:frame];<span class="hljs-keyword">if (<span class="hljs-keyword">Self) {<span class="hljs-keyword">Self<span class="hljs-variable">. backgroundcolor = [<span class="hljs-built_in">Uicolor clearcolor]; _gridcolor = [<span class="hljs-built_in">Uicolor bluecolor]; _gridlinewidth = single_line_width; _gridspacing =<span class="hljs-number">30; }<span class="hljs-keyword">Return<span class="hljs-keyword">self;} - (<span class="hljs-keyword">Void) Setgridcolor: (<span class="hljs-built_in">Uicolor *) Gridcolor{_gridcolor = gridcolor; [<span class="hljs-keyword">Self setneedsdisplay];} - (<span class="hljs-keyword">Void) Setgridspacing: (<span class="hljs-built_in">Cgfloat) gridspacing{_gridspacing = gridspacing; [<span class="hljs-keyword">Self setneedsdisplay];} - (<span class="hljs-keyword">Void) Setgridlinewidth: (<span class="hljs-built_in">Cgfloat) gridlinewidth{_gridlinewidth = gridlinewidth; [<span class="hljs-keyword">Self setneedsdisplay];}<span class="hljs-comment">Only override Drawrect:if perform custom drawing.<span class="hljs-comment">An empty implementation adversely affects performance during animation.-(<span class="hljs-keyword">Void) Drawrect: (<span class="hljs-built_in">Cgrect) rect{<span class="hljs-built_in">Cgcontextref context =<span class="hljs-built_in">Uigraphicsgetcurrentcontext ();<span class="hljs-built_in">Cgcontextbeginpath (context);<span class="hljs-built_in">CGFloat Linemargin =<span class="hljs-keyword">Self<span class="hljs-variable">. gridspacing;<span class="hljs-comment">/** * https://developer.apple.com/library/ios/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/ graphicsdrawingoverview/graphicsdrawingoverview.html * The drawing position needs to be adjusted only when the lineweight to be drawn is an odd number of pixels */<span class="hljs-built_in">CGFloat Pixeladjustoffset =<span class="hljs-number">0;<span class="hljs-keyword">If (((<span class="hljs-keyword">Int) (<span class="hljs-keyword">Self<span class="hljs-variable">. gridlinewidth * [<span class="hljs-built_in">UIScreen mainscreen]<span class="hljs-variable">. Scale) +<span class="hljs-number">1)%<span class="hljs-number">2 = =<span class="hljs-number">0) {pixeladjustoffset = single_line_adjust_offset;}<span class="hljs-built_in">CGFloat XPos = linemargin-pixeladjustoffset;<span class="hljs-built_in">CGFloat YPos = linemargin-pixeladjustoffset;<span class="hljs-keyword">While (xPos <<span class="hljs-keyword">Self<span class="hljs-variable">. Bounds<span class="hljs-variable">. Size<span class="hljs-variable">. Width) {<span class="hljs-built_in">Cgcontextmovetopoint (context, xPos,<span class="hljs-number">0);<span class="hljs-built_in">Cgcontextaddlinetopoint (context, xPos,<span class="hljs-keyword">Self<span class="hljs-variable">. Bounds<span class="hljs-variable">. Size<span class="hljs-variable">. height); XPos + = linemargin; }<span class="hljs-keyword">While (yPos <<span class="hljs-keyword"><span class="hljs-keyword">self<span class="hljs-variable">.bounds<span class="hljs-variable">.size<span class="hljs-variable">.height) {<span class="hljs-built_in">cgcontextmovetopoint (context, <span class="hljs-number">0, yPos); <span class="hljs-built_in">cgcontextaddlinetopoint (context, <span class="hljs-keyword">self <span class="hljs-variable">.bounds<span class="hljs-variable">.size<span class="hljs-variable">.width, yPos); YPos + = linemargin; } <span class="hljs-built_in">cgcontextsetlinewidth (context, <span class="hljs-keyword">self <span class="hljs-variable">.gridlinewidth); <span class="hljs-built_in">cgcontextsetstrokecolorwithcolor (context, <span class="hljs-keyword">self<span class="hljs-variable">.gridcolor<span class="hljs-built_in" . cgcolor); <span>cgcontextstrokepath (context); <span class="hljs-keyword"> @end </span> </span> </span> </span> </span> </span> </span> </span> </span> </span> </span> </span> </span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></span></code></pre><p><p>Here's How to use It:</p></p><pre><pre><code class="hljs objectivec">SvGridView *gridView = [[SvGridView alloc] initWithFrame:<span class="hljs-keyword">self<span class="hljs-variable">.view<span class="hljs-variable">.bounds];gridView<span class="hljs-variable">.autoresizingMask = <span class="hljs-built_in">UIViewAutoresizingFlexibleWidth | <span class="hljs-built_in">UIViewAutoresizingFlexibleHeight;gridView<span class="hljs-variable">.alpha = <span class="hljs-number">0.6;gridView<span class="hljs-variable">.gridColor = [<span class="hljs-built_in">UIColor greenColor];[<span class="hljs-keyword">self<span class="hljs-variable">.view addSubview:gridView];</span></span></span></span></span></span></span></span></span></span></span></span></code></pre></pre><p><p></p></p>A city problems<p><p>All right, Here we go. the whole knowledge of this article is over, and finally I have a question.</p></p><pre><pre><code class="hljs">设计师为什么一定要一个像素的线?</code></pre></pre><p><p>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.<br><br></p></p>
Related Article

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.