16-核心動畫

畫板(圖片處理)

  • 為了能對照片提供更多的手勢操作,需要把從相冊中選取的照片放置到UIImageView中,然后對控件添加手勢操作即可完成對照片的對應(yīng)操作
  • 創(chuàng)建一個專門用來處理圖片的View(ImageHandleView)

隱式動畫

  • 只有非根層view的layer才有隱式動畫,根層view的layer沒有隱式動畫

時鐘動畫

  • 首先定義宏,每秒鐘秒針、每分鐘分針、每小時時針和每分鐘時針旋轉(zhuǎn)的度數(shù)
// 一秒鐘秒針轉(zhuǎn)6°
#define perSecondA 6

// 一分鐘分針轉(zhuǎn)6°
#define perMinuteA 6

// 一小時時針轉(zhuǎn)30°
#define perHourA 30

// 每分鐘時針轉(zhuǎn)多少度
#define perMinuteHourA 0.5
  • 時鐘界面的搭建
@interface ViewController ()

@property (weak, nonatomic) IBOutlet UIImageView *clockView;

@property (nonatomic, weak) CALayer *secondLayer;

@property (nonatomic, weak) CALayer *minuteLayer;

@property (nonatomic, weak) CALayer *hourLayer;

@end
  • 在viewDidLoad中對界面進行初始化
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    // 添加時針,因為先添加的在下面
    [self setUpHourLayer];
    
    // 添加分針
    [self setUpMinuteLayer];
    
    // 添加秒針
    [self setUpSecondLayer];
    
    // 添加定時器
    [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeChange) userInfo:nil repeats:YES];
    
    [self timeChange];
    
}
  • 以此初始化各個指針
#pragma mark - 添加秒針
- (void)setUpSecondLayer
{
   CALayer *secondL = [CALayer layer];
    
    secondL.backgroundColor = [UIColor redColor].CGColor;
    
    // 設(shè)置錨點
    secondL.anchorPoint = CGPointMake(0.5, 1);
    
    secondL.position = CGPointMake(kClockW * 0.5, kClockW * 0.5);
    
    secondL.bounds = CGRectMake(0, 0, 1, kClockW * 0.5 - 20);
    
    [_clockView.layer addSublayer:secondL];
    
    _secondLayer = secondL;
}

#pragma mark - 添加分針
- (void)setUpMinuteLayer
{
    CALayer *layer = [CALayer layer];
    
    layer.backgroundColor = [UIColor blackColor].CGColor;
    
    // 設(shè)置錨點
    layer.anchorPoint = CGPointMake(0.5, 1);
    
    layer.position = CGPointMake(kClockW * 0.5, kClockW * 0.5);
    
    layer.bounds = CGRectMake(0, 0, 4, kClockW * 0.5 - 20);
    
    layer.cornerRadius = 4;
    
    [_clockView.layer addSublayer:layer];
    
    _minuteLayer = layer;
}

#pragma mark - 添加時針
- (void)setUpHourLayer
{
    CALayer *layer = [CALayer layer];
    
    layer.backgroundColor = [UIColor blackColor].CGColor;
    
    // 設(shè)置錨點
    layer.anchorPoint = CGPointMake(0.5, 1);
    
    layer.position = CGPointMake(kClockW * 0.5, kClockW * 0.5);
    
    layer.bounds = CGRectMake(0, 0, 4, kClockW * 0.5 - 40);
    
    layer.cornerRadius = 4;
    
    [_clockView.layer addSublayer:layer];
    
    _hourLayer = layer;
}
  • 定時器調(diào)用的方法
- (void)timeChange
{
    // 獲取當(dāng)前的系統(tǒng)的時間
    
    // 獲取當(dāng)前日歷對象
    NSCalendar *calendar = [NSCalendar currentCalendar];
    
    // 獲取日期的組件:年月日小時分秒
    // components:需要獲取的日期組件
    // fromDate:獲取哪個日期的組件
    // 經(jīng)驗:以后枚舉中有移位運算符,通常一般可以使用并運算(|)
    NSDateComponents  *cmp = [calendar components:NSCalendarUnitSecond | NSCalendarUnitMinute | NSCalendarUnitHour fromDate:[NSDate date]];
    
    // 獲取秒
    NSInteger second = cmp.second;
    
    // 獲取分
    NSInteger minute = cmp.minute;
    
    // 獲取小時
    NSInteger hour = cmp.hour;
    
    // 計算秒針轉(zhuǎn)多少度
    CGFloat secondA = second * perSecondA;
    
    // 計算分針轉(zhuǎn)多少度
    CGFloat minuteA = minute * perMinuteA;
    
    // 計算時針轉(zhuǎn)多少度
    CGFloat hourA = hour * perHourA + minute * perMinuteHourA;
    
    // 旋轉(zhuǎn)秒針
    _secondLayer.transform = CATransform3DMakeRotation(angle2radion(secondA), 0, 0, 1);
    
    // 旋轉(zhuǎn)分針
    _minuteLayer.transform = CATransform3DMakeRotation(angle2radion(minuteA), 0, 0, 1);
    
    // 旋轉(zhuǎn)小時
    _hourLayer.transform = CATransform3DMakeRotation(angle2radion(hourA), 0, 0, 1);
}

核心動畫(CABasicAnimation)

  • 創(chuàng)建動畫-->描述修改哪個屬性產(chǎn)生動畫-->設(shè)置值-->設(shè)置動畫執(zhí)行的次數(shù)-->取消動畫反彈-->將動畫添加到layer上
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 創(chuàng)建動畫
    CABasicAnimation *anim = [CABasicAnimation animation];
    
    // 描述下修改哪個屬性產(chǎn)生動畫
    // anim.keyPath = @"position";
    // 只能是layer屬性
    anim.keyPath = @"transform.scale";
    
    // 設(shè)置值
    // anim.toValue = [NSValue valueWithCGPoint:CGPointMake(250, 500)];
    
    anim.toValue = @0.5;
    
    // 設(shè)置動畫執(zhí)行次數(shù)
    anim.repeatCount = MAXFLOAT;
    
    // 取消動畫反彈
    // 設(shè)置動畫完成的時候不要移除動畫
    anim.removedOnCompletion = NO;
    
    // 設(shè)置動畫執(zhí)行完成要保持最新的效果
    anim.fillMode = kCAFillModeForwards;
    
    [_imageV.layer addAnimation:anim forKey:nil];
    
}

核心動畫(CAKeyFrameAnimation)

  • 開始觸摸時,創(chuàng)建UIBezierPath并設(shè)置起點
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // touch
    UITouch *touch = [touches anyObject];
    
    // 獲取手指的觸摸點
    CGPoint curP = [touch locationInView:self];
    
    // 創(chuàng)建路徑
    UIBezierPath *path = [UIBezierPath bezierPath];
    _path = path;
    
    // 設(shè)置起點
    [path moveToPoint:curP];
    
}
  • 觸摸移動時,獲取觸摸點并添加路徑
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    // touch
    UITouch *touch = [touches anyObject];
    
    // 獲取手指的觸摸點
    CGPoint curP = [touch locationInView:self];
    
    [_path addLineToPoint:curP];
    
    [self setNeedsDisplay];
}
  • 結(jié)束觸摸時,給imageView添加核心動畫
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 給imageView添加核心動畫
    // 添加核心動畫
    
    CAKeyframeAnimation *anim = [CAKeyframeAnimation animation];
    
    anim.keyPath = @"position";
    
    // anim.values = @[@(angle2Radion(-10)),@(angle2Radion(10)),@(angle2Radion(-10))];
    
    anim.path = _path.CGPath;
    
    anim.duration = 1;
    
    anim.repeatCount = MAXFLOAT;
    
    [[[self.subviews firstObject] layer] addAnimation:anim forKey:nil];
}

核心動畫(CATransition)

  • CATransition即轉(zhuǎn)場動畫
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    
    // 轉(zhuǎn)場代碼
    if (i == 4) {
        i = 1;
    }
    // 加載圖片名稱
    NSString *imageN = [NSString stringWithFormat:@"%d",i];
    
    _imageView.image = [UIImage imageNamed:imageN];
    
    i++;
    
    // 轉(zhuǎn)場動畫
    CATransition *anim = [CATransition animation];
    
    anim.type = @"pageCurl";
    
    anim.duration = 2;
    
    [_imageView.layer addAnimation:anim forKey:nil];
    
}

核心動畫(CAAnimationGroup)

  • CAAnimationGroup即動畫組
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    // 同時縮放,平移,旋轉(zhuǎn)
    CAAnimationGroup *group = [CAAnimationGroup animation];
    
    CABasicAnimation *scale = [CABasicAnimation animation];
    scale.keyPath = @"transform.scale";
    scale.toValue = @0.5;
    
    CABasicAnimation *rotation = [CABasicAnimation animation];
    rotation.keyPath = @"transform.rotation";
    rotation.toValue = @(arc4random_uniform(M_PI));
    
    CABasicAnimation *position = [CABasicAnimation animation];
    position.keyPath = @"position";
    position.toValue = [NSValue valueWithCGPoint:CGPointMake(arc4random_uniform(200), arc4random_uniform(200))];
    
    group.animations = @[scale,rotation,position];
    
    [_redView.layer addAnimation:group forKey:nil];
    
}

UIView和核心動畫(Core Animation)的區(qū)別

  • 通過分別使用UIView動畫和核心動畫觀察,核心動畫并不會真實的改變圖層的屬性值

  • 而UIView動畫必須通過修改屬性的真實值,才會有動畫效果

  • 如果以后做動畫的時候,不需要與用戶交互,通常使用核心動畫(比如轉(zhuǎn)場效果)

  • 注意:核心動畫中,取消反彈的代碼必須放在圖層添加動畫之前

      anim.removedOnCompletion = NO;
      anim.fillMode = kCAFillModeForwards;
      [self.redView.layer addAnimation:anim forKey:nil];
    
  • 核心動畫要想監(jiān)聽動畫的完成,需要實現(xiàn)代理,但是不需要遵守任何協(xié)議

// 動畫完成的時候調(diào)用
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
{
    NSLog(@"%@", NSStringFromCGPoint(_redView.layer.position));
}
  • UIView動畫在完成的時候,可以使用block定義動畫完成后要執(zhí)行的代碼
    [UIView animateWithDuration:0.25 animations:^{
        
        _redView.layer.position = CGPointMake(150, 400);

    } completion:^(BOOL finished) {

            NSLog(@"%@", NSStringFromCGPoint(_redView.layer.position));

        }];

轉(zhuǎn)盤的設(shè)計

  • 首先是界面的搭建,直接從xib中加載即可,創(chuàng)建一個類方法返回xib所對應(yīng)的View
+ (instancetype)wheelView
{
   return  [[NSBundle mainBundle] loadNibNamed:@"WheelView" owner:nil options:nil][0];
}
  • 注意:initWithCoder:方法只是在加載xib的時候會調(diào)用,但是并不會將xib中的控件和代碼進行連線
  • 所以需要在awakeFromNib方法中,進行添加和設(shè)置按鈕的操作等
- (void)awakeFromNib
{
    // UIImageView是個比較特殊的View,默認不會與用戶進行交互,需要設(shè)置userInteractionEnabled為YES
    _centerView.userInteractionEnabled = YES;
    CGFloat btnW = 68;
    CGFloat btnH = 143;
    
     CGFloat wh = self.bounds.size.width;
    
    // 加載大圖片
    UIImage *bigImage = [UIImage imageNamed:@"LuckyAstrology"];
    
    // 加載大圖片
    UIImage *selBigImage = [UIImage imageNamed:@"LuckyAstrologyPressed"];
    
    // 獲取當(dāng)前使用的圖片像素和點的比例
    CGFloat scale = [UIScreen mainScreen].scale;
    CGFloat imageW = bigImage.size.width / 12 * scale;
    CGFloat imageH = bigImage.size.height * scale;
    // CGImageRef image:需要裁減的圖片
    // rect:裁減區(qū)域
    // 裁減區(qū)域是以像素為基準
    // CGImageCreateWithImageInRect(CGImageRef image, CGRect rect)
    
    // 添加按鈕
    for (int i = 0; i < 12; i++) {
        WheelButton *btn = [WheelButton buttonWithType:UIButtonTypeCustom];
        
        // 設(shè)置按鈕的位置
        btn.layer.anchorPoint = CGPointMake(0.5, 1);
        
        btn.bounds = CGRectMake(0, 0, btnW, btnH);
        
        btn.layer.position = CGPointMake(wh * 0.5, wh * 0.5);
        
        // 按鈕的旋轉(zhuǎn)角度
        CGFloat radion = (30 * i) / 180.0 * M_PI;
        
        btn.transform = CGAffineTransformMakeRotation(radion);
        
        [_centerView addSubview:btn];
        
        // 加載按鈕的圖片
        // 計算裁減區(qū)域
        CGRect clipR = CGRectMake(i * imageW, 0, imageW, imageH);
        
        // 裁減圖片
        CGImageRef imgR =  CGImageCreateWithImageInRect(bigImage.CGImage, clipR);
        
        UIImage *image = [UIImage imageWithCGImage:imgR];
        
        // 設(shè)置按鈕的圖片
        [btn setImage:image forState:UIControlStateNormal];
        
        // 設(shè)置選中狀態(tài)下圖片
        imgR = CGImageCreateWithImageInRect(selBigImage.CGImage, clipR);

        image = [UIImage imageWithCGImage:imgR];
        
        // 設(shè)置按鈕的圖片
        [btn setImage:image forState:UIControlStateSelected];
        
        // 設(shè)置選中背景圖片
        [btn setBackgroundImage:[UIImage imageNamed:@"LuckyRototeSelected"] forState:UIControlStateSelected];
        
        // 監(jiān)聽按鈕的點擊
        [btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
        
        // 默認選中第一個
        if (i == 0) {
            [self btnClick:btn];
        }
        
    }
}

- (void)btnClick:(UIButton *)btn
{
    _selBtn.selected = NO;
    btn.selected = YES;
    _selBtn = btn;
}
  • 開始旋轉(zhuǎn)的時候,使用CABasicAnimation創(chuàng)建動畫,并添加到self.centerView的layer上
#pragma mark - 開始旋轉(zhuǎn)
- (void)start
{
    CABasicAnimation *anim = [CABasicAnimation animation];
    
    anim.keyPath = @"transform.rotation";
    
    anim.toValue = @(M_PI * 2);
    
    anim.duration = 2;
    
    anim.repeatCount = MAXFLOAT;
    
    [_centerView.layer addAnimation:anim forKey:nil];
}
  • 當(dāng)需要修改系統(tǒng)控件的屬性的時候,需要自定義控件并集成系統(tǒng)的控件,重寫其中的方法即可
// 設(shè)置UIImageView的尺寸
// contentRect:按鈕的尺寸
- (CGRect)imageRectForContentRect:(CGRect)contentRect
{
    // 計算UIImageView控件尺寸
    CGFloat imageW = 40;
    CGFloat imageH = 46;
    CGFloat imageX = (contentRect.size.width - imageW) * 0.5;
    CGFloat imageY = 20;
    return CGRectMake(imageX, imageY, imageW, imageH);
}

// 取消高亮狀態(tài)
- (void)setHighlighted:(BOOL)highlighted
{
    
}
最后編輯于
?著作權(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)容

  • 在iOS中隨處都可以看到絢麗的動畫效果,實現(xiàn)這些動畫的過程并不復(fù)雜,今天將帶大家一窺iOS動畫全貌。在這里你可以看...
    F麥子閱讀 5,270評論 5 13
  • 在iOS中隨處都可以看到絢麗的動畫效果,實現(xiàn)這些動畫的過程并不復(fù)雜,今天將帶大家一窺ios動畫全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,696評論 6 30
  • Core Animation Core Animation,中文翻譯為核心動畫,它是一組非常強大的動畫處理API,...
    45b645c5912e閱讀 3,158評論 0 21
  • 在iOS實際開發(fā)中常用的動畫無非是以下四種:UIView動畫,核心動畫,幀動畫,自定義轉(zhuǎn)場動畫。 1.UIView...
    請叫我周小帥閱讀 3,326評論 1 23
  • 7、不使用IB是,下面這樣做有什么問題? 6、請說說Layer和View的關(guān)系,以及你是如何使用它們的。 1.首先...
    AlanGe閱讀 991評論 0 1

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