- - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
- {
- CGFloat width = 10.0f;
-
-
- CGContextSetLineWidth(ctx, width);
- CGContextSetStrokeColorWithColor(ctx, [UIColor redColor].CGColor);
-
- 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);
-
- CGContextStrokeEllipseInRect(ctx, rect);
- }
接上次,修改了一下,呵呵,看着舒服多了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的代碼你會看到以下結果佈局
- - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
- {
- CGFloat width = 10.0f;
-
-
- CGContextSetLineWidth(ctx, width);
- CGContextSetStrokeColorWithColor(ctx, [UIColor redColor].CGColor);
-
- 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);
-
- CGContextStrokeEllipseInRect(ctx, rect);
-
- layer.frame = CGRectMake(10.0f, 10.0f, 200.0f, 200.0f);
- }
還有須要注意在操做transform時,如旋轉時,frame會從新計算,此時frame的寬高再也不和bounds比配。如圖學習
下面再說說anchorPoint這個屬性,不少人對於使用此屬性可能會迷惑,究竟是怎麼設置的,先看張圖this
anchorPoint從{0.5, 0.5}變爲{0, 0},layer向右下偏移了,下面你們能夠用一下作個試驗atom
仍是使用上面的例子,在- (void)viewDidLoad的[blueLayerdisplay];前增長spa
- NSLog(@"%@", NSStringFromCGPoint(blueLayer.anchorPoint));
- NSLog(@"%@", NSStringFromCGPoint(blueLayer.position));
是爲了記錄變化前的值,接着在- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx中
增長對anchorPoint的設置,自已能夠任意設置看看結果
- - (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
- {
- CGFloat width = 10.0f;
-
-
- CGContextSetLineWidth(ctx, width);
- CGContextSetStrokeColorWithColor(ctx, [UIColor redColor].CGColor);
-
- 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);
-
- CGContextStrokeEllipseInRect(ctx, rect);
- layer.anchorPoint = CGPointMake(0, 0);
- NSLog(@"%@", NSStringFromCGPoint(layer.position));
- }
咱們能夠得出結論,anchorPoint能夠簡單地看做是設置左上頂點相對於中心position的位置,
計數以左上頂點到position的距離與寬高的比例,X軸方向正爲左移負爲右移,Y軸方向正爲上移負爲下移。
下面咱們用例子來看看具體的應用,具體代碼請查看例子3.1
源碼在這裏下載:http://www.informit.com/title/9780133440751
- - (void)viewDidLoad
- {
- [super viewDidLoad];
-
-
- self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0
- target:self
- selector:@selector(tick)
- userInfo:nil
- repeats:YES];
-
-
- [self tick];
- }
-
- - (void)tick
- {
-
- NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
- NSUInteger units = NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
- NSDateComponents *components = [calendar components:units fromDate:[NSDate date]];
-
-
- CGFloat hourAngle = (components.hour / 12.0) * M_PI * 2.0;
-
-
- CGFloat minuteAngle = (components.minute / 60.0) * M_PI * 2.0;
-
-
- CGFloat secondAngle = (components.second / 60.0) * M_PI * 2.0;
-
-
- self.hourHand.transform = CGAffineTransformMakeRotation(hourAngle);
- self.minuteHand.transform = CGAffineTransformMakeRotation(minuteAngle);
- self.secondHand.transform = CGAffineTransformMakeRotation(secondAngle);
- }
運行看看結果
發現什麼了沒有?CGAffineTransformMakeRotation以View的center點在旋轉
再看例子3.2,修改代碼
- - (void)viewDidLoad
- {
- [super viewDidLoad];
-
-
- self.secondHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
- self.minuteHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
- self.hourHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
-
-
- self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0
- target:self
- selector:@selector(tick)
- userInfo:nil
- repeats:YES];
-
-
- [self tick];
- }
看結果
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代碼
- - (void)viewDidLoad
- {
- [super viewDidLoad];
-
-
- self.view.layer.geometryFlipped = YES;
- self.secondHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
- self.minuteHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
- self.hourHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
-
-
- self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0
- target:self
- selector:@selector(tick)
- userInfo:nil
- repeats:YES];
-
-
- [self tick];
- }
本身運行看看,指針反着轉了。
再修改看看的geometryFlipped sublayers的做用域,呵呵暫且這麼說
首先增長一個view做爲secondHand的父view,修改代碼
增長
- @property (weak, nonatomic) IBOutlet UIView *sView;
- - (void)viewDidLoad
- {
- [super viewDidLoad];
-
-
- self.view.layer.geometryFlipped = YES;
- self.sView.layer.geometryFlipped = YES;
- self.secondHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
- self.minuteHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
- self.hourHand.layer.anchorPoint = CGPointMake(0.5f, 0.9f);
-
-
- self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0
- target:self
- selector:@selector(tick)
- userInfo:nil
- repeats:YES];
-
-
- [self tick];
- }
看結果
秒針正常了
咱們之前接觸的UIView是2維座標,但如今CAlayer確實3維座標,增長了Z軸, zPosition 和 anchorPointZ
看例子3.3,zPosition默認值爲0,當設置self.greenView.layer.zPosition大於0時,greenView將遮蓋redView
運行結果
例子3.4和3.5是對
- - (CALayer *)hitTest:(CGPoint)p;
-
- - (BOOL)containsPoint:(CGPoint)p;
兩個函數的,本身去看