iOS 高级动画应用:一个带缓冲效果的时钟

2019-08-07  本文已影响0人  某非著名程序员
时钟.gif

  如果你仔细观看,你会发现秒钟的有个慢起步,加速后重重落下,并不是机械的匀速的转动。总共用到动画的三个特性:transform、anchorPoint、UIViewAnimationOptionCurveEaseInOut。

来看看实现的过程:

1.界面搭建
  时、分、秒钟是三个UIImageView,三张图片相对于时钟图片是居中显示。


时钟图片

2.使用transform属性
  可使用transform按想要的角度来旋转时、分、秒三张图片,来达到效果。

//定义
@interface AnchorPointViewController ()
@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 AnchorPointViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    //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);
}

- (void)viewWillAppear:(BOOL)animated{
    [super viewWillAppear:animated];
    //start timer
    self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0
                                                  target:self
                                                selector:@selector(tickWithTimer:)
                                                userInfo:@(YES)
                                                 repeats:YES];
    
    //set initial hand positions
    [self tickWithAnimation:NO];
}

- (void)viewWillDisappear:(BOOL)animated{
    [super viewWillDisappear:animated];
    [self.timer invalidate];
    self.timer = nil;
}

- (void)tickWithTimer:(NSTimer *)timer{
    BOOL animation = [[timer userInfo] boolValue];
    [self tickWithAnimation:animation];
}

- (void)tickWithAnimation:(BOOL)animation
{
    //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]];
    //calculate hour hand angle
    CGFloat hourAngle = (components.hour / 12.0) * M_PI * 2.0;
    //calculate minute hand angle
    CGFloat minuteAngle = (components.minute / 60.0) * M_PI * 2.0;
    //calculate second hand angle
    CGFloat secondAngle = (components.second / 60.0) * M_PI * 2.0;
    if (animation) {
        [UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
            self.hourHand.transform = CGAffineTransformMakeRotation(hourAngle);
            self.minuteHand.transform = CGAffineTransformMakeRotation(minuteAngle);
            self.secondHand.transform = CGAffineTransformMakeRotation(secondAngle);
        } completion:^(BOOL finished) {
            
        }];
    }else{
        self.hourHand.transform = CGAffineTransformMakeRotation(hourAngle);
        self.minuteHand.transform = CGAffineTransformMakeRotation(minuteAngle);
        self.secondHand.transform = CGAffineTransformMakeRotation(secondAngle);
    }
     
}
@end

  启动一个定时器,每秒刷新下,CGAffineTransformMakeRotation这个方法需要注意的,旋转的是角度,所以需要手动换算。大多数开发者到这一步是没有问题的。看看效果:


时钟效果1.gif

  你会发现秒钟的旋转是围绕中心点旋转的,我们怎么挪动图片的位置都达不到想要的效果。
  这个时候就需要引入anchorPoint了。先来看看anchorPoint的解释:
默认来说, anchorPoint 位于图层的中点,所以图层的将会以这个点为中心放置。但是图层的 anchorPoint 可以被移动,比如你可以把它置于图层 frame 的左上角,于是图层的内容将会向右下角的 position 方向移动,而不是居中了。我们可以移动图层的anchorPoint,增加以下几行代码:

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

时钟效果2.gif

  这次能正常的移动了,但还不够完美。在显示世界中,钟表指针转动的时候,通常起步很慢,然后迅速啪地一声,最后缓冲到终点。
  苹果为我们提供了一个特性,动画是可以有速度的,我们可以使用UIView中的UIViewAnimationOptionCurveEaseInOut属性:

UIViewAnimationOptionCurveEaseInOut:缓慢启动缓慢结束
UIViewAnimationOptionCurveEaseIn:缓慢启动
UIViewAnimationOptionCurveEaseOut:缓慢结束
UIViewAnimationOptionCurveLinear:匀速启动匀速结束

[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
            self.hourHand.transform = CGAffineTransformMakeRotation(hourAngle);
            self.minuteHand.transform = CGAffineTransformMakeRotation(minuteAngle);
            self.secondHand.transform = CGAffineTransformMakeRotation(secondAngle);
        } completion:^(BOOL finished) {
            
        }];

  最后的效果就是本文的内容,都说苹果的动画做的很好,其中很多特性值得我们去挖掘,平时使用的动画根本就没发挥出苹果动画的十分之一,苹果的代码调试界面都是3D的。同样自己也能写出带层级的3D视图。
  本章内容来源:<<iOS CoreAnimation>>第3章图层几何学、第8章显示动画、第10章缓冲,并非原创。有兴趣的读者可自行阅读,阅读书籍比文章的理解来的更为深刻。

上一篇 下一篇

猜你喜欢

热点阅读