IOS Core Animation Advanced Techniques的學習筆記(二)

[objc]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片轉載學習
  1. - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx  
  2. {  
  3.     CGFloat width = 10.0f;  
  4.   
  5.     //draw a thick red circle  
  6.     CGContextSetLineWidth(ctx, width);  
  7.     CGContextSetStrokeColorWithColor(ctx, [UIColor redColor].CGColor);  
  8.   
  9.     CGRect rect = CGRectMake(layer.bounds.origin.x+width/2, layer.bounds.origin.y+width/2, layer.bounds.size.width-width, layer.bounds.size.height-width);  
  10.   
  11.     CGContextStrokeEllipseInRect(ctx, rect);  
  12. }  

接上次,修改了一下,呵呵,看着舒服多了xcode

因而可知線寬的擴展方式是同時向兩邊擴展的。app

 

 

 

第三章:Layer Geometryless

 

「Let no one unversed in geometry enter here.」
看到做者的信心了吧,你有了嗎?函數

 

UIView的佈局屬性有frame,bounds和center,CALayer一樣有3個對應frame,bounds和position。如圖:oop

 

須要注意的是,frame不是一個獨立的屬性,它是由bounds,position,transform等其餘屬性計算而來,因此改變frame會影響其餘屬性,反之改變其餘屬性也會影響frame。若是我在前面的例子裏增長一行改變frame的代碼你會看到以下結果佈局

 

[objc]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx  
  2. {  
  3.     CGFloat width = 10.0f;  
  4.   
  5.     //draw a thick red circle  
  6.     CGContextSetLineWidth(ctx, width);  
  7.     CGContextSetStrokeColorWithColor(ctx, [UIColor redColor].CGColor);  
  8.   
  9.     CGRect rect = CGRectMake(layer.bounds.origin.x+width/2, layer.bounds.origin.y+width/2, layer.bounds.size.width-width, layer.bounds.size.height-width);  
  10.   
  11.     CGContextStrokeEllipseInRect(ctx, rect);  
  12.   
  13.     layer.frame = CGRectMake(10.0f, 10.0f, 200.0f, 200.0f);  
  14. }  


 

還有須要注意在操做transform時,如旋轉時,frame會從新計算,此時frame的寬高再也不和bounds比配。如圖學習

 

下面再說說anchorPoint這個屬性,不少人對於使用此屬性可能會迷惑,究竟是怎麼設置的,先看張圖this

 

anchorPoint從{0.5, 0.5}變爲{0, 0},layer向右下偏移了,下面你們能夠用一下作個試驗atom

仍是使用上面的例子,在- (void)viewDidLoad的[blueLayerdisplay];前增長spa

 

[objc]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. NSLog(@"%@", NSStringFromCGPoint(blueLayer.anchorPoint));  
  2. NSLog(@"%@", NSStringFromCGPoint(blueLayer.position));  

是爲了記錄變化前的值,接着在- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx中

 

增長對anchorPoint的設置,自已能夠任意設置看看結果

 

[objc]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx  
  2. {  
  3.     CGFloat width = 10.0f;  
  4.   
  5.     //draw a thick red circle  
  6.     CGContextSetLineWidth(ctx, width);  
  7.     CGContextSetStrokeColorWithColor(ctx, [UIColor redColor].CGColor);  
  8.   
  9.     CGRect rect = CGRectMake(layer.bounds.origin.x+width/2, layer.bounds.origin.y+width/2, layer.bounds.size.width-width, layer.bounds.size.height-width);  
  10.   
  11.     CGContextStrokeEllipseInRect(ctx, rect);  
  12.     layer.anchorPoint = CGPointMake(0, 0);  
  13.     NSLog(@"%@", NSStringFromCGPoint(layer.position));  
  14. }  


咱們能夠得出結論,anchorPoint能夠簡單地看做是設置左上頂點相對於中心position的位置,

 

計數以左上頂點到position的距離與寬高的比例,X軸方向正爲左移負爲右移,Y軸方向正爲上移負爲下移。

 

下面咱們用例子來看看具體的應用,具體代碼請查看例子3.1

 

源碼在這裏下載:http://www.informit.com/title/9780133440751

 
[objc]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. - (void)viewDidLoad  
  2. {  
  3.     [super viewDidLoad];  
  4.   
  5.     //start timer  
  6.     self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0  
  7.                                                   target:self  
  8.                                                 selector:@selector(tick)  
  9.                                                 userInfo:nil  
  10.                                                  repeats:YES];  
  11.       
  12.     //set initial hand positions  
  13.     [self tick];  
  14. }  
  15.   
  16. - (void)tick  
  17. {  
  18.     //convert time to hours, minutes and seconds  
  19.     NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];  
  20.     NSUInteger units = NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;  
  21.     NSDateComponents *components = [calendar components:units fromDate:[NSDate date]];  
  22.       
  23.     //calculate hour hand angle  
  24.     CGFloat hourAngle = (components.hour / 12.0) * M_PI * 2.0;  
  25.       
  26.     //calculate minute hand angle  
  27.     CGFloat minuteAngle = (components.minute / 60.0) * M_PI * 2.0;  
  28.       
  29.     //calculate second hand angle  
  30.     CGFloat secondAngle = (components.second / 60.0) * M_PI * 2.0;  
  31.       
  32.     //rotate hands    
  33.     self.hourHand.transform = CGAffineTransformMakeRotation(hourAngle);  
  34.     self.minuteHand.transform = CGAffineTransformMakeRotation(minuteAngle);  
  35.     self.secondHand.transform = CGAffineTransformMakeRotation(secondAngle);  
  36. }  

運行看看結果

發現什麼了沒有?CGAffineTransformMakeRotation以View的center點在旋轉

再看例子3.2,修改代碼

 

[objc]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. - (void)viewDidLoad  
  2. {  
  3.     [super viewDidLoad];  
  4.       
  5.     //adjust anchor points  
  6.     self.secondHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f); // 爲何不是1.0f?  
  7.     self.minuteHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);  
  8.     self.hourHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);  
  9.   
  10.     //start timer  
  11.     self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0  
  12.                                                   target:self  
  13.                                                 selector:@selector(tick)  
  14.                                                 userInfo:nil  
  15.                                                  repeats:YES];  
  16.       
  17.     //set initial hand positions  
  18.     [self tick];  
  19. }  

看結果

 

CGAffineTransformMakeRotation以layer的position點在旋轉

 

相對座標的轉換函數,UIView使用:

 

- (CGPoint)convertPoint:(CGPoint)point toView:(UIView *)view;

- (CGPoint)convertPoint:(CGPoint)point fromView:(UIView *)view;

- (CGRect)convertRect:(CGRect)rect toView:(UIView *)view;

- (CGRect)convertRect:(CGRect)rect fromView:(UIView *)view;

CALayer使用:

 

- (CGPoint)convertPoint:(CGPoint)p fromLayer:(CALayer *)l;

- (CGPoint)convertPoint:(CGPoint)p toLayer:(CALayer *)l;

- (CGRect)convertRect:(CGRect)r fromLayer:(CALayer *)l;

- (CGRect)convertRect:(CGRect)r toLayer:(CALayer *)l;

 

 

注意:直到OS X 10.8纔出現了geometryFlipped屬性,該屬性能夠改變默認圖層y座標的方向。當翻轉變換被調用時,使用該屬性來調整圖層的方向有的時候是必需的。若是父視圖使用了翻轉變換,它的子視圖內容(以及它對應的圖層)將常常被顛倒。在這種狀況下,設置子圖層的geometryFlipped屬性爲YES是一種修正該問題最簡單的方法。在OS X 10.8及以上版本,AppKit負責管理該屬性,你不該該更改它。對於iOS app,不推薦使用geometryFlipped屬性。


「This is a BOOL value that determines whether the geometry of a layer is vertically flipped with respect to its superlayer. Setting this property to YES for a layer on iOS means that its sublayers will be flipped vertically and will be positioned relative to the bottom of its bounds rather than the top as normal (as will all of their sublayers, and so on, unless they also have YES for their geometryFlipped property).」
注意的是geometryFlipped只對sublayers起做用,只到有sub也設置了YES才恢復,有點負負得正的意思

修改例子3.2代碼

 

 

[objc]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. - (void)viewDidLoad  
  2. {  
  3.     [super viewDidLoad];  
  4.       
  5.     //adjust anchor points  
  6.     self.view.layer.geometryFlipped = YES;  
  7.     self.secondHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);  
  8.     self.minuteHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);  
  9.     self.hourHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);  
  10.   
  11.     //start timer  
  12.     self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0  
  13.                                                   target:self  
  14.                                                 selector:@selector(tick)  
  15.                                                 userInfo:nil  
  16.                                                  repeats:YES];  
  17.       
  18.     //set initial hand positions  
  19.     [self tick];  
  20. }  

 

本身運行看看,指針反着轉了。

再修改看看的geometryFlipped sublayers的做用域,呵呵暫且這麼說
首先增長一個view做爲secondHand的父view,修改代碼

 

增長

 

[objc]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. @property (weak, nonatomic) IBOutlet UIView *sView;  

 

 

[objc]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. - (void)viewDidLoad  
  2. {  
  3.     [super viewDidLoad];  
  4.       
  5.     //adjust anchor points  
  6.     self.view.layer.geometryFlipped = YES;  
  7.     self.sView.layer.geometryFlipped = YES;  
  8.     self.secondHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);  
  9.     self.minuteHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);  
  10.     self.hourHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);  
  11.   
  12.     //start timer  
  13.     self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0  
  14.                                                   target:self  
  15.                                                 selector:@selector(tick)  
  16.                                                 userInfo:nil  
  17.                                                  repeats:YES];  
  18.       
  19.     //set initial hand positions  
  20.     [self tick];  
  21. }  

看結果

 

秒針正常了

 

咱們之前接觸的UIView是2維座標,但如今CAlayer確實3維座標,增長了Z軸, zPosition 和 anchorPointZ
看例子3.3,zPosition默認值爲0,當設置self.greenView.layer.zPosition大於0時,greenView將遮蓋redView

運行結果

 

例子3.4和3.5是對

 

[objc]  view plain copy print ? 在CODE上查看代碼片 派生到個人代碼片
  1. /* Returns the farthest descendant of the layer containing point 'p'. 
  2.  * Siblings are searched in top-to-bottom order. 'p' is defined to be 
  3.  * in the coordinate space of the receiver's nearest ancestor that 
  4.  * isn't a CATransformLayer (transform layers don't have a 2D 
  5.  * coordinate space in which the point could be specified). */  
  6. - (CALayer *)hitTest:(CGPoint)p;  
  7.   
  8. /* Returns true if the bounds of the layer contains point 'p'. */  
  9. - (BOOL)containsPoint:(CGPoint)p;  

 

兩個函數的,本身去看

相關文章
相關標籤/搜索