3

私は、毎秒更新されるこのように、時計の針に秒針の動きを表示しようとしているiPadアプリに取り組んでいます。

- (void) updateClock:(NSTimer *)theTimer{
    dateComponents = [[NSCalendar currentCalendar] components:(NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit) fromDate:[NSDate date]];
    seconds = [dateComponents second];
    minutes = [dateComponents minute];
    hours = [dateComponents hour];
    secAngle = Degrees2Radians(seconds/60.0*360);
    minAngle = Degrees2Radians(minutes/60.0*360);
    hourAngle = Degrees2Radians(hours/24.0*360) + minAngle/24.0;
    secHand.transform = CATransform3DMakeRotation (secAngle+M_PI, 0, 0, 1);
    hourHand.transform = CATransform3DMakeRotation (hourAngle+M_PI, 0, 0, 1);
    minHand.transform = CATransform3DMakeRotation (minAngle+M_PI, 0, 0, 1);
}

- (void)start{
    timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateClock:) userInfo:nil repeats:YES];
}

ただし、現在の動作方法では、毎秒カチカチ音をたてているように見えます。しかし、私が本当に欲しいのは、レイヤーをアニメーション化して、1 分間で 0 から 360 までスムーズに 0 から 360 まで完全に回転して連続的に動いているように見えるようにすることです。回転するので、秒針には次のものを使用しました。

-(void)startSmooth{
    started = YES;
    CABasicAnimation *fullRotation;
    fullRotation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
    fullRotation.fromValue = [NSNumber numberWithFloat:0];
    fullRotation.toValue = [NSNumber numberWithFloat:((360*M_PI)/180)];
    fullRotation.duration = 60.0f;
    fullRotation.repeatCount = HUGE_VALF;
    [secHand addAnimation:fullRotation forKey:@"360"];
}

ただし、これに関する問題は、常に 0 度の角度で回転を開始するため、針は、時間に関係なく常に 30 秒から動き始めているように見えることです。

私がやりたいのは、秒針があるはずの実際のポイントから開始することです。どうすればそれを達成できますか?

4

3 に答える 3

4

実際には2つの問題があります:アニメーション化する最良の方法とミリ秒を取得する方法

NSTimerベースのアニメーションの代替

CADisplayLinkコアアニメーションではなく、コアアニメーションの使用を検討することをお勧めしNSTimerます。

まず、CADisplayLinkプロパティを作成できます。

@property (nonatomic, strong) CADisplayLink *displayLink;

次に、表示リンクを設定して開始できます。

- (void)startDisplayLink
{
    self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(handleDisplayLink:)];
    [self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}

次に、時計の手描きロジックをここに配置できます。

- (void)handleDisplayLink:(CADisplayLink *)displayLink
{
    // update your clock hands here
}

最後に、表示リンクを停止する必要がある場合は、次の電話をかけることができます。

- (void)stopDisplayLink
{
    [self.displayLink invalidate];
    self.displayLink = nil;
}

ミリ秒を取得する方法

最初はアニメーションの問題に焦点を当てていると思っていましたが、問題の根本はNSDateComponents悲しいことにミリ秒ではないということです。ミリ秒を取得する方法はたくさんありますが、日付フォーマッターを使用するだけかもしれません。

NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = @"hh:mm:ss.SSS";
NSString *string = [formatter stringFromDate:[NSDate date]];
NSArray *timeComponents = [string componentsSeparatedByString:@":"];

// if time was 09:48:17.197, then

NSInteger hour = [timeComponents[0] integerValue];    // 9
NSInteger min = [timeComponents[1] integerValue];     // 48
CGFloat floatSec = [timeComponents[2] floatValue];    // 17.197

また、秒針のように時針と分針をスイープする場合は、それらの小数値も計算できます。

CGFloat floatMin = min + (floatSec / 60.0);           // 48.287
CGFloat floatHour = hour + (floatMin / 60.0);         // 9.805
于 2013-03-03T23:07:05.600 に答える
3

fromValue と toValue の代わりに fromValue と byValue を使用して、開発者ドキュメントを使用して自分の質問に対する答えを見つけました。

変更する必要があるだけです:

-(void)startSmooth{
    CABasicAnimation *fullRotationSec;
    fullRotationSec = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
    fullRotationSec.fromValue = [NSNumber numberWithFloat:secAngle+M_PI];
    fullRotationSec.byValue = [NSNumber numberWithFloat:((360*M_PI)/180)];
    fullRotationSec.duration = 60.0f;
    fullRotationSec.repeatCount = HUGE_VALF;
    [secHandView addAnimation:fullRotation forKey:@"360"];
}
于 2013-03-05T22:12:07.020 に答える
0

私は最近、タイマーに基づいて文字盤を描くことについてのこのSOの質問に答えました。このアニメーションは、それを呼び出すために使用されるタイマーの間隔に応じて、任意の頻度(任意のレベルの「滑らかさ」)で実行できます。

下部にある呼び出しコードを参照してください。タイマー間隔を0.1秒などの小さな値に変更するだけです。

于 2013-03-03T21:25:04.197 に答える