成人免费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

源代碼

2010-02-03 15:40:37

Python函數

2019-11-14 16:23:07

MySQL索引數據庫

2013-01-07 11:38:54

VMware認證

2020-05-09 10:48:34

數據備份存儲數據

2010-06-08 10:35:38

UML圖

2018-04-20 10:54:52

數據集成數據科學工具

2015-03-31 14:15:12

JavaJava事件通知

2012-09-17 09:58:02

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

2022-11-24 09:55:12

Kubernetes監控

2015-05-19 09:53:41

AWS漏洞管理云漏洞管理

2009-12-03 20:09:03

Tomcat支持PHP

2016-09-30 09:49:05

2010-02-02 14:11:14

Python 進行編程

2010-02-03 14:37:10

Python 開發環境

2020-02-04 14:25:29

云遷移云計算云平臺

2018-04-23 14:58:27

大數據

2012-12-27 14:14:05

Android開發保存文件
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 免费成人在线网站 | av在线免费观看网站 | 一区二区视频在线 | 亚洲欧美综合 | 久久激情视频 | 综合久久av | 中文字幕免费视频 | 日韩三| 国产日韩电影 | 日韩av免费在线电影 | 蜜月va乱码一区二区三区 | 国产精品九九视频 | 午夜私人影院 | 精品视频一区二区三区在线观看 | 日韩在线一区二区 | av黄色在线| 99精品视频免费观看 | 成人a视频| 免费国产视频 | 亚洲欧美日韩国产 | 91在线精品一区二区 | 国产高清精品一区二区三区 | 毛片在线免费播放 | 91精品在线播放 | 亚洲国产一区二区三区 | 精品国产乱码久久久久久88av | 成人精品鲁一区一区二区 | 美女久久久久久久 | 久久一本| www.色综合| 99久久精品国产一区二区三区 | www精品美女久久久tv | 国产亚洲精品精品国产亚洲综合 | 久久国产三级 | 亚洲人成在线观看 | 欧美视频 亚洲视频 | 亚洲欧美一区二区三区1000 | 欧美一级免费 | 日本精品久久久久 | 国产一区二区精品在线 | 日韩欧美一级精品久久 |