畫板(圖片處理)
- 為了能對照片提供更多的手勢操作,需要把從相冊中選取的照片放置到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
{
}