iOS 動畫學(xué)習(xí)

gitbook地址

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

  1. 通過繼承UIView并實現(xiàn)-drawRect:方法來自定義繪制
  2. 實現(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的寬高不再一致了,如圖


86114FA1-BE8E-4CFE-BFC0-9D1974E48DAD.png
錨點(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

效果圖:

257239BF-BFF4-4B78-9C16-42EA2A7CFF7B.png

改變錨點之后:

- (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);
}

效果圖:

FEBD2E9B-230C-4E7B-8C30-154BCA1DCCD7.png
坐標(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;
CB9B3017-2752-46F8-922D-2874BA055958.png

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:

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容