CALayer的幾個屬性和方法
contents:
// 你給contents賦的不是CGImage,那么你得到的圖層將是空白的
layer.contents = (__bridge id)image.CGImage;
contentGravity:
// UIView有一個叫做contentMode,CALayer對應(yīng)的屬性叫做contentGravity
contentsScale:
// 寄宿圖的像素尺寸和視圖大小的比例
// 如果contentsScale設(shè)置為1.0,將會以每個點1個像素繪制圖片,如果設(shè)置為2.0,則會以每個點2個像素繪制圖片
layer.contentsScale = [UIScreen mainScreen].scale;
maskToBounds:
// UIView有一個叫做clipsToBounds,CALayer對應(yīng)的屬性叫做masksToBounds
contentsRect:
// contentsRect是{0, 0, 1, 1},按比例
// contentsRect{0,0,0.5,0.5} 則是左上角四分之一的圖
contentsCenter:
// contentsCenter其實是一個CGRect,它定義了一個固定的邊框和一個在圖層上可拉伸的區(qū)域
// 氣泡拉伸,android的.9圖片
Custom Drawing
- 通過繼承UIView并實現(xiàn)-drawRect:方法來自定義繪制
- 實現(xiàn)CALayerDelegate:
/**
* 1.設(shè)置delegate
* 2. 調(diào)用display
* 3. 實現(xiàn)drawLayer:方法,方法內(nèi)繪圖
*/
CALayer *blueLayer = [CALayer layer];
blueLayer.delegate = self;
[blueLayer display];
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)ctx
{
//draw a thick red circle
CGContextSetLineWidth(ctx, 10.0f);
CGContextSetStrokeColorWithColor(ctx, [UIColor redColor].CGColor);
CGContextStrokeEllipseInRect(ctx, layer.bounds);
}
總結(jié):
CALayerDelegate繪制:寄宿圖不會自動重繪它的內(nèi)容,決定權(quán)交給了開發(fā)者,通過調(diào)用display。
UIView的-drawRect繪制:UIView會幫你做完剩下的工作,無需手動調(diào)用display。
圖層幾何學(xué)
布局:
frame:代表了圖層的外部坐標(biāo)(也就是在父圖層上占據(jù)的空間)
bounds:是內(nèi)部坐標(biāo)({0, 0}通常是圖層的左上角)
center和position:都代表了相對于父圖層anchorPoint所在的位置
注意:frame并不是一個非常清晰的屬性,它其實是一個虛擬屬性,是根據(jù)bounds,position和transform計算而來,改變frame的值同樣會影響到他們當(dāng)中的值
注意:當(dāng)對圖層做變換的時候,比如旋轉(zhuǎn)或者縮放,frame實際上代表了覆蓋在圖層旋轉(zhuǎn)之后的整個軸對齊的矩形區(qū)域,也就是說frame的寬高可能和bounds的寬高不再一致了,如圖
錨點(anchorPoint)(注意:center和position都代表了相對于父圖層anchorPoint所在的位置)
默認(rèn)位置:anchorPoint位于圖層的中點
大小范圍:{0,0}->{1,1} (contentsRect和contentsCenter屬性類似)
錨點的作用:eg 實現(xiàn)一個??
@interface ViewController ()
@property (nonatomic, weak) IBOutlet UIImageView *hourHand;
@property (nonatomic, weak) IBOutlet UIImageView *minuteHand;
@property (nonatomic, weak) IBOutlet UIImageView *secondHand;
@property (nonatomic, weak) NSTimer *timer;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
//start timer
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(tick) userInfo:nil repeats:YES];
//set initial hand positions
[self tick];
}
- (void)tick
{
//convert time to hours, minutes and seconds
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSUInteger units = NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
NSDateComponents *components = [calendar components:units fromDate:[NSDate date]];
CGFloat hoursAngle = (components.hour / 12.0) * M_PI * 2.0;
//calculate hour hand angle //calculate minute hand angle
CGFloat minsAngle = (components.minute / 60.0) * M_PI * 2.0;
//calculate second hand angle
CGFloat secsAngle = (components.second / 60.0) * M_PI * 2.0;
//rotate hands
self.hourHand.transform = CGAffineTransformMakeRotation(hoursAngle);
self.minuteHand.transform = CGAffineTransformMakeRotation(minsAngle);
self.secondHand.transform = CGAffineTransformMakeRotation(secsAngle);
}
@end
效果圖:
改變錨點之后:
- (void)viewDidLoad
{
[super viewDidLoad];
// adjust anchor points
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);
}
效果圖:
坐標(biāo)系
z坐標(biāo)軸
zPosition:控制視圖層級,越大的處于視圖越上面,上面的視圖會遮擋下面的視圖(可以改變屏幕上圖層的順序,但不能改變事件傳遞的順序)
anchorPointZ:z方向錨點
layer的方法:
containsPoint:接受一個在本圖層坐標(biāo)系下的CGPoint,如果這個點在圖層frame范圍內(nèi)就返回YES
hitTest:返回圖層本身,或者包含這個坐標(biāo)點的葉子節(jié)點圖層(測算的順序嚴(yán)格依賴于圖層樹當(dāng)中的圖層順序)
視覺效果
conrnerRadius: 圓角角度
masksToBounds: 裁剪
borderWidth:邊框?qū)挾?br>
borderColor:邊框顏色
shadowColor:陰影顏色
shadowOffset:陰影的方向和距離
shadowRadius:陰影模糊度
shadowPath:陰影的樣式
// shadowPath使用:
//create a square shadow
CGMutablePathRef squarePath = CGPathCreateMutable();
CGPathAddRect(squarePath, NULL, self.layerView1.bounds);
self.layerView1.layer.shadowPath = squarePath; CGPathRelease(squarePath);
//create a circular shadow
CGMutablePathRef circlePath = CGPathCreateMutable();
CGPathAddEllipseInRect(circlePath, NULL, self.layerView2.bounds);
self.layerView2.layer.shadowPath = circlePath; CGPathRelease(circlePath);
// 如果是一個矩形或者是圓,用CGPath會相當(dāng)簡單明了。但是如果是更加復(fù)雜一點的圖形,UIBezierPath類會更合適
陰影的裁剪:(用一個額外的視圖來解決陰影裁切的問題)
內(nèi)層:設(shè)置masksToBounds = yes
外層:設(shè)置masksToBounds = no and shadow。
CALayer屬性mask,蒙板原理實現(xiàn)不規(guī)則裁剪
//create mask layer
CALayer *maskLayer = [CALayer layer];
maskLayer.frame = self.layerView.bounds;
UIImage *maskImage = [UIImage imageNamed:@"Cone.png"];
maskLayer.contents = (__bridge id)maskImage.CGImage;
//apply mask to image layer
self.imageView.layer.mask = maskLayer;
CALayer蒙板圖層真正厲害的地方在于蒙板圖不局限于靜態(tài)圖。任何有圖層構(gòu)成的都可以作為mask屬性,這意味著你的蒙板可以通過代碼甚至是動畫實時生成。
layer拉伸與裁剪
layer.magnificationFilter
// 圖片拉伸算法
kCAFilterLinear
kCAFilterNearest
kCAFilterTrilinear
//set up digit views
for (UIView *view in self.digitViews) {
//set contents
view.layer.contents = (__bridge id)digits.CGImage;
view.layer.contentsRect = CGRectMake(0, 0, 0.1, 1.0);
view.layer.contentsGravity = kCAGravityResizeAspect;
}
組透明
CALayer屬性:opacity(等同UIView的alpha的屬性來確定視圖的透明度。)
CALayer屬性:shouldRasterize(來實現(xiàn)組透明的效果,如果它被設(shè)置為YES,在應(yīng)用透明度之前,圖層及其子圖層都會被整合成一個整體的圖片,然后再透明)
//enable rasterization for the translucent button
button2.layer.shouldRasterize = YES;
button2.layer.rasterizationScale = [UIScreen mainScreen].scale;
// 設(shè)置rasterizationScale屬性去匹配屏幕,以防止出現(xiàn)Retina屏幕像素化的問題
變換
專用圖層
CAShapeLayer: