成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

iOS: 如何正確的繪制1像素的線

移動開發
為了獲得良好的視覺效果,繪圖系統通常都會采用一個叫“antialiasing(反鋸齒)”的技術,iOS也不例外。 顯示屏幕有很多小的顯示單元組成,可以接單的理解為一個單元就代表一個像素。如果要畫一條黑線,條線剛好落在了一列或者一行顯示顯示單元之內,將會渲染出標準的一個像素的黑線。 但如果線落在了兩個行或列的中間時,那么會得到一條“失真”的線,其實是兩個像素寬的灰線。

 [[140291]]

一、Point Vs Pixel

iOS中當我們使用Quartz,UIKit,CoreAnimation等框架時,所有的坐標系統采用Point來衡量。系統在實際渲染到設置時會幫助我們處理Point到Pixel的轉換。

這樣做的好處隔離變化,即我們在布局的事后不需要關注當前設備是否為Retina,直接按照一套坐標系統來布局即可。

實際使用中我們需要牢記下面這一點:

  1. One point does not necessarily correspond to one physical pixel. 

1 Point的線在非Retina屏幕則是一個像素,在Retina屏幕上則可能是2個或者3個,取決于系統設備的DPI。

iOS系統中,UIScreen,UIView,UIImage,CALayer類都提供相關屬性來獲取scale factor。

原生的繪制技術天然的幫我們處理了scale factor,例如在drawRect:方法中,UIKit自動的根據當前運行的設備設置了正切的scale factor。所以我們在drawRect: 方法中繪制的任何內容都會被自動縮放到設備的物理屏幕上。

基于以上信息可以看出,我們大部分情況下都不需要去關注pixel,然而存在部分情況需要考慮像素的轉化。

例如畫1個像素的分割線

看到這個問題你的***想法可能是,直接根據當前屏幕的縮放因子計算出1 像素線對應的Point,然后設置線寬即可。

代碼如下:

  1. 1.0f / [UIScreen mainScreen].scale 

表面上看著一切正常了,但是通過實際的設備測試你會發現渲染出來的線寬并不是1個像素。

Why?

為了獲得良好的視覺效果,繪圖系統通常都會采用一個叫“antialiasing(反鋸齒)”的技術,iOS也不例外。

顯示屏幕有很多小的顯示單元組成,可以接單的理解為一個單元就代表一個像素。如果要畫一條黑線,條線剛好落在了一列或者一行顯示顯示單元之內,將會渲染出標準的一個像素的黑線。

但如果線落在了兩個行或列的中間時,那么會得到一條“失真”的線,其實是兩個像素寬的灰線。

如下圖所示:

blob.png

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

官方解釋如上,簡單翻譯一下:

  1. 規定:奇數像素寬度的線在渲染的時候將會表現為柔和的寬度擴展到向上的整數寬度的線,
  2. 除非你手動的調整線的位置,使線剛好落在一行或列的顯示單元內。 

如何對齊呢?

  1. On a low-resolution display (with a scale factor of 1.0), a one-point-wide line 
  2. is one pixel wide. To avoid antialiasing when you draw a one-point-wide horizontal or vertical line, 
  3. if the line is an odd number of pixels in width, you must offset the position by 0.5 points to 
  4. either side of a whole-numbered position. If the line is an even number of points in width, 
  5. to avoid a fuzzy line, you must not do so. 
  6. On a high-resolution display (with a scale factor of 2.0), a line that is one point wide is 
  7. not antialiased at all because it occupies two full pixels (from -0.5 to +0.5). 
  8. To draw a line that covers only a single physical pixel, you would need to make it 0.5 points in thickness and offset its position by 0.25 points. A comparison between the two types of screens is shown in Figure 1-4. 

翻譯一下

 
 
 
  1. 在非高清屏上,一個Point對應一個像素。為了防止“antialiasing”導致的奇數像素的線渲染時出現失真,你需要設置偏移0.5 Point。
  2. 在高清屏幕上,要繪制一個像素的線,需要設置線寬為0.5個Point,同事設置偏移為0.25 Point。
  3. 如果線寬為偶數Point的話,則不要去設置偏移,否則線條也會失真。

如下圖所示:

blob.png

看了上述一通解釋,我們了解了1像素寬的線條失真的原因,及解決辦法。

至此問題貌似都解決了?再想想為什么在非Retina和Retina屏幕上調整位置時值不一樣,前者為0.5Point,后者為0.25Point,那么scale為3的6 Plus設備又該調整多少呢?

要回答這個問題,我們需要理解調整多少依舊什么原則。

blob.png

再回過頭來看看這上面的圖片,圖片中每一格子代表一個像素,而頂部標記的則代碼我們布局時的坐標。

可以看到左邊的非Retina屏幕,我們要在(3,0)這個位置畫一條一個像素寬的豎線時,由于渲染的最小單位是像素,而(3,0)這個坐標恰好位于兩個像素中間,此時系統會對坐標3左右兩列的像素對填充,為了不至于線顯得太寬,為對線的顏色淡化。那么根據上述信息我們可以得出,如果要畫出一個像素寬的線,就得把繪制的坐標移動到(2.5, 0)或者(3.5,0)這個位置,這樣系統渲染的時候剛好可以填充一列像素,也就是標準的一個像素的線。

基于上面的分析,我們可以得出“Scale為3的6 Plus”設備如果要繪制1個像素寬的線條時,位置調整也應該是0.5像素,對應該的Point計算如下:

  1. (1.0f / [UIScreen mainScreen].scale) / 2

奉上一個畫一像素線的一個宏:

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

使用代碼如下:

  1. CGFloat xPos = 5
  2. UIView *view = [[UIView alloc] initWithFrame:CGrect(x - SINGLE_LINE_ADJUST_OFFSET, 0, SINGLE_LINE_WIDTH, 100)]; 

#p#

二、正確的繪制Grid線條

貼上一個寫的GridView的代碼,代碼中對Grid線條的奇數像素做了偏移,防止出現線條模糊的情況。

SvGridView.h

 
  1. // 
  2. //  SvGridView.h 
  3. //  SvSinglePixel 
  4. // 
  5. //  Created by xiaoyong.cxy on 6/23/15. 
  6. //  Copyright (c) 2015 smileEvday. All rights reserved. 
  7. // 
  8. #import @interface SvGridView : UIView 
  9. /** 
  10.  * @brief 網格間距,默認30 
  11.  */ 
  12. @property (nonatomic, assign) CGFloat   gridSpacing; 
  13. /** 
  14.  * @brief 網格線寬度,默認為1 pixel (1.0f / [UIScreen mainScreen].scale) 
  15.  */ 
  16. @property (nonatomic, assign) CGFloat   gridLineWidth; 
  17. /** 
  18.  * @brief 網格顏色,默認藍色 
  19.  */ 
  20. @property (nonatomic, strong) UIColor   *gridColor; 
  21. @end 

SvGridView.m

  1. // 
  2. //  SvGridView.m 
  3. //  SvSinglePixel 
  4. // 
  5. //  Created by xiaoyong.cxy on 6/23/15. 
  6. //  Copyright (c) 2015 smileEvday. All rights reserved. 
  7. // 
  8. #import "SvGridView.h" 
  9. #define SINGLE_LINE_WIDTH           (1 / [UIScreen mainScreen].scale) 
  10. #define SINGLE_LINE_ADJUST_OFFSET   ((1 / [UIScreen mainScreen].scale) / 2
  11. @implementation SvGridView 
  12. @synthesize gridColor = _gridColor; 
  13. @synthesize gridSpacing = _gridSpacing; 
  14. - (instancetype)initWithFrame:(CGRect)frame 
  15.     self = [super initWithFrame:frame]; 
  16.     if (self) { 
  17.         self.backgroundColor = [UIColor clearColor]; 
  18.           
  19.         _gridColor = [UIColor blueColor]; 
  20.         _gridLineWidth = SINGLE_LINE_WIDTH; 
  21.         _gridSpacing = 30
  22.     } 
  23.       
  24.     return self; 
  25. - (void)setGridColor:(UIColor *)gridColor 
  26.     _gridColor = gridColor; 
  27.       
  28.     [self setNeedsDisplay]; 
  29. - (void)setGridSpacing:(CGFloat)gridSpacing 
  30.     _gridSpacing = gridSpacing; 
  31.       
  32.     [self setNeedsDisplay]; 
  33. - (void)setGridLineWidth:(CGFloat)gridLineWidth 
  34.     _gridLineWidth = gridLineWidth; 
  35.       
  36.     [self setNeedsDisplay]; 
  37. // Only override drawRect: if you perform custom drawing. 
  38. // An empty implementation adversely affects performance during animation. 
  39. - (void)drawRect:(CGRect)rect 
  40.     CGContextRef context = UIGraphicsGetCurrentContext(); 
  41.       
  42.     CGContextBeginPath(context); 
  43.     CGFloat lineMargin = self.gridSpacing; 
  44.       
  45.     /** 
  46.      *  https://developer.apple.com/library/ios/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/GraphicsDrawingOverview/GraphicsDrawingOverview.html 
  47.      * 僅當要繪制的線寬為奇數像素時,繪制位置需要調整 
  48.      */ 
  49.     CGFloat pixelAdjustOffset = 0
  50.     if (((int)(self.gridLineWidth * [UIScreen mainScreen].scale) + 1) % 2 == 0) { 
  51.         pixelAdjustOffset = SINGLE_LINE_ADJUST_OFFSET; 
  52.     } 
  53.       
  54.     CGFloat xPos = lineMargin - pixelAdjustOffset; 
  55.     CGFloat yPos = lineMargin - pixelAdjustOffset; 
  56.     while (xPos < self.bounds.size.width) { 
  57.         CGContextMoveToPoint(context, xPos, 0); 
  58.         CGContextAddLineToPoint(context, xPos, self.bounds.size.height); 
  59.         xPos += lineMargin; 
  60.     } 
  61.       
  62.     while (yPos < self.bounds.size.height) { 
  63.         CGContextMoveToPoint(context, 0, yPos); 
  64.         CGContextAddLineToPoint(context, self.bounds.size.width, yPos); 
  65.         yPos += lineMargin; 
  66.     } 
  67.       
  68.     CGContextSetLineWidth(context, self.gridLineWidth); 
  69.     CGContextSetStrokeColorWithColor(context, self.gridColor.CGColor); 
  70.     CGContextStrokePath(context); 
  71. @end 

使用方法如下:

 
  1. SvGridView *gridView = [[SvGridView alloc] initWithFrame:self.view.bounds]; 
  2. gridView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; 
  3. gridView.alpha = 0.6
  4. gridView.gridColor = [UIColor greenColor]; 
  5. [self.view addSubview:gridView]; 

三、一個問題

好了,到這兒本文的全部知識就結束了,***我還有一個問題。

設計師為什么一定要一個像素的線?

一個像素的線可能在非Retina設備上顯示寬度看著合適,在Retina屏幕上顯示可能會比較細。是不是一定需要一個像素的線,需要根據情況來處理。

責任編輯:倪明 來源: cnblog
相關推薦

2015-10-12 11:06:36

Web前端0.5像素

2010-02-03 17:42:30

2016-10-11 16:28:11

源代碼

2020-05-09 10:48:34

數據備份存儲數據

2010-02-03 15:40:37

Python函數

2019-11-14 16:23:07

MySQL索引數據庫

2013-01-07 11:38:54

VMware認證

2018-07-20 09:16:08

微軟瀏覽器Windows

2018-04-20 10:54:52

數據集成數據科學工具

2015-03-31 14:15:12

JavaJava事件通知

2012-09-17 09:58:02

云集成平臺云集成集成平臺

2009-12-03 20:09:03

Tomcat支持PHP

2022-11-24 09:55:12

Kubernetes監控

2015-05-19 09:53:41

AWS漏洞管理云漏洞管理

2010-06-08 10:35:38

UML圖

2012-12-24 09:07:09

iOSUnity3D

2018-03-30 10:26:24

行間距行高iOS

2016-09-30 09:49:05

2010-02-02 14:11:14

Python 進行編程

2010-02-03 14:37:10

Python 開發環境
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 一级在线观看 | 精品亚洲一区二区三区 | 亚洲欧洲日韩精品 中文字幕 | 成人在线观看网址 | 成人一级黄色毛片 | 一级一片在线观看 | 久久久一区二区 | 在线91| 9久久精品 | 国产视频久久久 | 免费国产一区二区 | 欧美成人一级 | www日本在线播放 | 久久综合一区 | 午夜a v电影 | 日本不卡免费新一二三区 | 综合亚洲视频 | 女同久久另类99精品国产 | 国产分类视频 | 亚洲一区二区中文字幕 | 国产日韩欧美在线播放 | 国产在线第一页 | av永久| 午夜电影网| 国产黄视频在线播放 | 国产精品久久久久久久久久久新郎 | 午夜小视频在线观看 | 国产精品福利在线观看 | 欧美一级免费片 | 国产 亚洲 网红 主播 | 一级亚洲 | 国产成人精品视频在线观看 | 亚洲精品成人免费 | 欧美一级电影免费观看 | a级片在线观看 | 成人免费视频 | 免费观看的av | 国产91精品久久久久久久网曝门 | 久久69精品久久久久久久电影好 | 日韩欧美中文字幕在线观看 | 99精品网站|