所有的動畫、繪圖、這里全搞定

看著我這標(biāo)題就覺得有點狂啊,其實是本人最近工作有點閑,看了很多人寫的sample,從中萃取精華,總結(jié)下,以防止自己忘記了,豈不白白浪費了這幾天的努力。廢話就這么多,現(xiàn)在開始正題:
先說說咱這篇文章會講到什么吧,首先我會講講繪圖,然后講講動畫
咱們首先從繪圖說起,

  • 使用CoreGraphics進(jìn)行繪圖
    說到繪圖,那繪圖是在哪里繪呢,當(dāng)然是在View里面了,我們可以重寫UIView的- (void)drawRect:(CGRect)rect方法,然后在里面進(jìn)行繪圖,繪圖的話就離不來CoreGraphics了,然而CoreGraphics的核心就是QuzCore里面的幾個函數(shù)了。廢話少說,直接上代碼
    - (void)drawRect:(CGRect)rect {
    // 獲取繪圖上下文環(huán)境
    CGContextRef context = UIGraphicsGetCurrentContext();
    // 設(shè)置線條的寬度
    CGContextSetLineWidth(context, 4.0);
    // 設(shè)置線條的顏色
    CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
    // 將繪畫筆移到一個點作為繪圖的起點
    CGContextMoveToPoint(context, 20.0, 20.0);
    // 由起點畫一條線到終點
    CGContextAddLineToPoint(context, 300, 400);
    // 畫出來
    CGContextStrokePath(context);
    }
    這段代碼之后呈現(xiàn)出的效果如下:

如你所見,這段代碼的功能是畫了一條紅色的斜線。當(dāng)然如果你想畫一個矩形的話也是同樣的一個道理,在上面的代碼后面加上如下代碼就好:

// 畫一個矩形
CGRect arect = CGRectMake(200, 30, 49, 59);
// 設(shè)置填充色
CGContextSetFillColorWithColor(context, [UIColor blueColor].CGColor);
// 填充矩形
CGContextFillRect(context, arect);
// 將舉行顯示出來
CGContextAddRect(context, arect);

效果的話自己去試吧,我就不上圖了,另外誰能告訴我怎么把圖片縮小,這太占地了。繪圖就說這么多了,感覺用處不大啊,以后感覺用處大再補充吧。

  • 使用CAShapeLayer 、UIBezierPath、CABasicAnimation畫
    經(jīng)??吹絼e人發(fā)出一下比較屌的動畫例子,其中用到的兩個必不可少的技術(shù)點有三個,分別是:
    CAShapeLayer:這是動畫的主要載體,動畫都是由他執(zhí)行
    UIBezierPath:用來描繪CAShapeLayer的邊界
    CABasicAnimation:動畫對象,由他對動畫的執(zhí)行過程進(jìn)行描述
    使用實例如下:
    #import "NibView.h"
    @interface NibView()

      // 執(zhí)行動畫的載體
      @property (nonatomic, strong) CAShapeLayer *shapLayer;
    
      @end
    
      @implementation NibView
    
      /*
      // Only override drawRect: if you perform custom drawing.
      // An empty implementation adversely affects performance during animation.
      - (void)drawRect:(CGRect)rect {
          // Drawing code
      }
      */
    
      // 畫面的初始化在此方法內(nèi)進(jìn)行
      - (id)initWithCoder:(NSCoder *)aDecoder {
          self = [super initWithCoder:aDecoder];
          self.frame = [UIApplication sharedApplication].keyWindow.bounds;
          self.backgroundColor = [UIColor redColor];
          
          UIBezierPath *bpath = [UIBezierPath bezierPath];
          [bpath moveToPoint:CGPointMake(100, 150)];
          [bpath addCurveToPoint:CGPointMake(300, 150)
                   controlPoint1:CGPointMake(200, 80)
                   controlPoint2:CGPointMake(200, 200)];
          [bpath addCurveToPoint:CGPointMake(300, 400)
                   controlPoint1:CGPointMake(400, 230)
                   controlPoint2:CGPointMake(250, 350)];
          [bpath addLineToPoint:CGPointMake(100, 400)];
          [bpath closePath];
          
          self.shapLayer.path = bpath.CGPath;
          
          [self.layer addSublayer:_shapLayer];
          
          return self;
      }
    
      // 獲得一個path
      - (UIBezierPath *)rectPath {
          UIBezierPath *rectpath = [UIBezierPath bezierPath];
          [rectpath moveToPoint:CGPointMake(100.0, 150.0)];
          [rectpath addLineToPoint:CGPointMake(300, 150)];
          [rectpath addLineToPoint:CGPointMake(300, 400)];
          [rectpath addLineToPoint:CGPointMake(100, 400)];
          [rectpath closePath];
          return rectpath;
      }
    
      // 執(zhí)行動畫
      - (void)animate {
          CABasicAnimation *expandAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
          expandAnimation.fromValue = (__bridge id)(_shapLayer.path);
          expandAnimation.toValue = (__bridge id)[self rectPath].CGPath;
          expandAnimation.beginTime = 0;
          expandAnimation.duration = 0.5;
          expandAnimation.fillMode = kCAFillModeForwards;
          expandAnimation.removedOnCompletion = NO;
          [self.shapLayer addAnimation:expandAnimation forKey:nil];
          
      }
    
      // 加個按鈕讓動畫可以重復(fù)進(jìn)行
      - (IBAction)goAnimate:(UIButton *)sender {
          [self animate];
      }
    
      #pragma mark - initViews
      - (CAShapeLayer *)shapLayer {
          if (!_shapLayer) {
              _shapLayer = [[CAShapeLayer alloc] init];
              _shapLayer.frame = self.bounds;
              _shapLayer.fillColor = [UIColor greenColor].CGColor;
          }
          return _shapLayer;
      }
    
      @end
    

下面對上面的代碼進(jìn)行說明:

  1. 我這里是將代碼動畫放在一個xib文件里面的,需要注意的是當(dāng)xib文件被加載時它調(diào)用的是- (id)initWithCoder:(NSCoder *)aDecoder這個方法,而不是- (id)initWithFrame:(CGRect)frame這個方法,使用初始化的事情都應(yīng)該放在這里面來進(jìn)行。
  2. 在animate這個方法里面有這么兩行
    expandAnimation.fillMode = kCAFillModeForwards;
    expandAnimation.removedOnCompletion = NO;
    需要注意的是這兩行要同時寫上動畫才不會回去。
    動畫執(zhí)行的效果如下:

另外你可以利用CAAnimationGroup來組織來管理動畫,使得幾個動畫連續(xù)執(zhí)行,這樣可以形成一系列的連貫動畫效果,例如:
#import "NibView.h"

    @interface NibView()

    // 執(zhí)行動畫的對戲那個
    @property (nonatomic, strong) CAShapeLayer *shapLayer;

    @end

    @implementation NibView

    /*
    // Only override drawRect: if you perform custom drawing.
    // An empty implementation adversely affects performance during animation.
    - (void)drawRect:(CGRect)rect {
        // Drawing code
    }
    */

    // 畫面的初始化在此方法內(nèi)進(jìn)行
    - (id)initWithCoder:(NSCoder *)aDecoder {
        self = [super initWithCoder:aDecoder];
        self.frame = [UIApplication sharedApplication].keyWindow.bounds;
        self.backgroundColor = [UIColor redColor];
        self.shapLayer.path = [self curvePath].CGPath;
        [self.layer addSublayer:_shapLayer];
        return self;
    }

    // 獲得一個飽含曲線的path
    - (UIBezierPath *)curvePath {
        UIBezierPath *bpath = [UIBezierPath bezierPath];
        [bpath moveToPoint:CGPointMake(70, 150)];
        [bpath addCurveToPoint:CGPointMake(270, 150)
                 controlPoint1:CGPointMake(170, 80)
                 controlPoint2:CGPointMake(170, 200)];
        [bpath addCurveToPoint:CGPointMake(270, 400)
                 controlPoint1:CGPointMake(370, 230)
                 controlPoint2:CGPointMake(220, 350)];
        [bpath addLineToPoint:CGPointMake(70, 400)];
        [bpath closePath];
        return bpath;
    }


    // 獲得一個path
    - (UIBezierPath *)rectPath {
        UIBezierPath *rectpath = [UIBezierPath bezierPath];
        [rectpath moveToPoint:CGPointMake(100.0, 150.0)];
        [rectpath addLineToPoint:CGPointMake(300, 150)];
        [rectpath addLineToPoint:CGPointMake(300, 400)];
        [rectpath addLineToPoint:CGPointMake(100, 400)];
        [rectpath closePath];
        return rectpath;
    }

    // 獲得一個正方形邊跡
    - (UIBezierPath *)suqarePath {
        UIBezierPath *squarPath = [UIBezierPath bezierPath];
        [squarPath moveToPoint:CGPointMake(10, 150)];
        [squarPath addLineToPoint:CGPointMake(310, 150)];
        [squarPath addLineToPoint:CGPointMake(310, 450)];
        [squarPath addLineToPoint:CGPointMake(10, 450)];
        [squarPath closePath];
        return squarPath;
    }


    // 執(zhí)行動畫
    - (void)animate {
        // 原始形態(tài)變成長方形
        CABasicAnimation *expandAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
        expandAnimation.fromValue = (__bridge id)(_shapLayer.path);
        expandAnimation.toValue = (__bridge id)[self rectPath].CGPath;
        expandAnimation.beginTime = 0;
        expandAnimation.duration = 0.5;
        [self.shapLayer addAnimation:expandAnimation forKey:nil];
        // 長方形變成正方形
        CABasicAnimation *expandAnimation2 = [CABasicAnimation animationWithKeyPath:@"path"];
        expandAnimation2.fromValue = (__bridge id)[self rectPath].CGPath;
        expandAnimation2.toValue = (__bridge id)[self suqarePath].CGPath;
        expandAnimation2.beginTime = expandAnimation.beginTime + expandAnimation.duration;
        expandAnimation2.duration = 0.5;
        // 正方形又回到原始形態(tài)
        CABasicAnimation *expandAnimation3 = [CABasicAnimation animationWithKeyPath:@"path"];
        expandAnimation3.fromValue = (__bridge id)[self suqarePath].CGPath;
        expandAnimation3.toValue = (__bridge id)(_shapLayer.path);
        expandAnimation3.beginTime = expandAnimation2.beginTime + expandAnimation2.duration;
        expandAnimation3.duration = 0.5;
        
        CAAnimationGroup *group = [CAAnimationGroup animation];
        group.animations = @[expandAnimation, expandAnimation2, expandAnimation3];
        group.beginTime = expandAnimation.beginTime;
        group.duration = expandAnimation3.beginTime + expandAnimation3.duration;
        group.fillMode = kCAFillModeForwards;
        group.removedOnCompletion = NO;
        group.repeatCount = 2;
        [self.shapLayer addAnimation:group forKey:nil];
        
    }

    // 加個按鈕讓動畫可以重復(fù)進(jìn)行
    - (IBAction)goAnimate:(UIButton *)sender {
        [self animate];
    }

    #pragma mark - initViews
    - (CAShapeLayer *)shapLayer {
        if (!_shapLayer) {
            _shapLayer = [[CAShapeLayer alloc] init];
            _shapLayer.frame = self.bounds;
            _shapLayer.fillColor = [UIColor greenColor].CGColor;
        }
        return _shapLayer;
    }

    @end

由于修改較大,使用干脆又重現(xiàn)全部貼了出來了,下面做以下說明:

  1. 首先為了代碼的整齊我把initWithCoder里面的畫邊界部分的代碼抽了出來,單獨形成了一個方法
  2. 我增加了一個返回正方形的軌跡方法suqarePath
  3. 我對animate方法進(jìn)行了修改,引入了CAAnimationGroup,這里仍需要注意的是fillMode和removedOnCompletion這兩個熟悉,現(xiàn)在把他應(yīng)用到動畫組上。
通過動畫組,我們可以形成各種細(xì)膩的動畫效果,一切貌似變的明朗起來.
  • 繞著Z軸旋轉(zhuǎn)的方法
    有一種動畫叫做旋轉(zhuǎn),對于旋轉(zhuǎn)來說如果像上面一樣一個個慢慢組的話會寫死你有木有。那旋轉(zhuǎn)動畫怎么玩呢,很簡單,看到我們上面聲明動畫是這么玩的:
    [CABasicAnimation animationWithKeyPath:@"path"],
    然而,現(xiàn)在我們將這么玩:
    [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]
    他們兩的區(qū)別就是KeyPath變了,看到這里,我們明白了,其實動畫的種類就是由這個東西決定的。是@"path"說明這個動畫是通過改變邊界來形成動畫,那很自然@"transform.rotation.z"就是繞著Z軸旋轉(zhuǎn)形成的動畫了。廢話不多說,再次上代碼:
    首先在類中加入如下方法
    // 旋轉(zhuǎn)動畫
    - (void)rotation {
    CABasicAnimation *rotaionAnimate = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    rotaionAnimate.toValue = @(M_PI * 2.0);
    rotaionAnimate.duration = 0.5;
    rotaionAnimate.removedOnCompletion = YES;
    [self.shapLayer addAnimation:rotaionAnimate forKey:nil];

      }
    

然后在修改goAnimate方法
- (CAShapeLayer *)shapLayer {
if (!_shapLayer) {
_shapLayer = [[CAShapeLayer alloc] init];
_shapLayer.frame = self.bounds;
_shapLayer.fillColor = [UIColor greenColor].CGColor;
}
return _shapLayer;
}

這里我們讓圖層旋轉(zhuǎn)360度,運行效果如下:



另外需要說明的是可以制定圖像繞著那一點旋轉(zhuǎn),我們只要指定它的描點,在rotation方法里面加入下面這句代碼
self.shapLayer.anchorPoint = CGPointMake(0.1, 0.1);
效果如下:



由于我們改變了描點,所以圖像的fram變了。
  • 描邊動畫
    有關(guān)描邊動畫也是改變一下KeyPath,它的KeyPath是:@"strokeEnd"
    在代碼中加入如下方法
    - (void)strokeBoard {
    self.shapLayer.strokeColor = [UIColor whiteColor].CGColor;
    self.shapLayer.lineWidth = 20.0;
    CABasicAnimation *strokeAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    strokeAnimation.fromValue = @0.0;
    strokeAnimation.toValue = @1.0;
    strokeAnimation.duration = 1.0;
    [self.shapLayer addAnimation:strokeAnimation forKey:nil];
    }
    然后在goAnimate方法里面加入如下代碼
    [NSTimer scheduledTimerWithTimeInterval:4.5
    target:self
    selector:@selector(strokeBoard)
    userInfo:nil
    repeats:NO];

這里strokeBoard方法里面我們設(shè)置了shapLayer的lineWidth和strokeColor,lineWidth默認(rèn)是0,strokeColor默認(rèn)是透明的。
當(dāng)lineWidth非0時,顯示方法是內(nèi)外各一半。為了便于觀察,這里運行前把上面的描點的那句代碼注釋掉,運行效果如下:


  • CAKeyframeAnimation:關(guān)鍵幀動畫。(和CABasicAnimation平行)就是一幀一幀的動畫了,一般用來處理GIF圖片的
    首先可以在View里面加入一張圖片,然后讓圖片抖動起來,抖動但動畫代碼如下:
    // 抖動動畫
    - (void)animate {
    // 定義幀動畫
    CAKeyframeAnimation animate = [CAKeyframeAnimation animation];
    // 改變弧度
    animate.values = @[@(M_PI/180
    5),@(-M_PI/1805),@(M_PI/1805)];
    // 關(guān)鍵幀是什么必須有,其實就是和什么有關(guān)的動畫了
    animate.keyPath = @"transform.rotation";
    // 重復(fù)次數(shù)
    animate.repeatCount = MAXFLOAT;
    animate.duration = 0.2;
    [_imageView.layer addAnimation:animate forKey:nil];
    }
    最后實現(xiàn)的效果如下:
抖動動畫
  • 動畫但暫停
    如果動畫時加在layer上的話,動畫是可以被暫停的,只需要將執(zhí)行動畫的那個layer的speed屬性設(shè)置為0就好,要回復(fù)的話設(shè)置成1.0就好
    如暫停和恢復(fù)上面的動畫:
    - (void)stopAnimate {

          // 獲取暫停時間
      //    CFTimeInterval pausedTime = [self.imageView.layer convertTime:CACurrentMediaTime() fromLayer:nil];
      //    
      //    self.imageView.layer.timeOffset = pausedTime;
    
          if (self.imageView.layer.speed == 0) {
              self.imageView.layer.speed = 1.0;
          } else {
              self.imageView.layer.speed = 0;
          }
      }
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Core Animation Core Animation,中文翻譯為核心動畫,它是一組非常強大的動畫處理API,...
    45b645c5912e閱讀 3,153評論 0 21
  • 顯式動畫 顯式動畫,它能夠?qū)σ恍傩宰鲋付ǖ淖远x動畫,或者創(chuàng)建非線性動畫,比如沿著任意一條曲線移動。 屬性動畫 ...
    清風(fēng)沐沐閱讀 2,091評論 1 5
  • 在iOS中隨處都可以看到絢麗的動畫效果,實現(xiàn)這些動畫的過程并不復(fù)雜,今天將帶大家一窺iOS動畫全貌。在這里你可以看...
    F麥子閱讀 5,261評論 5 13
  • 在iOS中隨處都可以看到絢麗的動畫效果,實現(xiàn)這些動畫的過程并不復(fù)雜,今天將帶大家一窺ios動畫全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,688評論 6 30
  • 金黃的麥田 彌散著撩人的氣息 詩歌譜寫完這成熟 該用什么來收獲 自然里裝不下的風(fēng)光 涌動在筆尖的勾勒 輕顏淡墨 為...
    無奈的無聊閱讀 279評論 0 1

友情鏈接更多精彩內(nèi)容