6

I'm making a speedometer app and I want arrow to behave the correct way - if I launch from zero to 200 km in one second, I want it to go around the bar, but if I set my rotation angle big enough, it goes the short way, from the bottom.
How do I make it go almost full circle and not via short path?

Here is the (trivial) code I use for rotation:

[UIView animateWithDuration:0.3 animations:^(){

        self.arrow.transform = CGAffineTransformRotate(CGAffineTransformIdentity, -4.4);

    }];

I figure I can rotate it in small chunks, but sometimes it may be needed to rotate it fast from zero to maximum (for example if we had no reading on speed and got it already at high speed so we need to rotate the arrow most of the screen).

As a side question - how do I queue animations, so that I can apply them one by one?

4

3 に答える 3

4

少し前に、以下に含まれるヘルパー関数を作成しました。基本的に、UIKit はこれには役に立ちません。QuartzCore フレームワークをインポートし、@ CAKeyframeAnimationPaul Cezanne が指摘したように、またはCABasicAnimationのいずれかを使用する必要があります。これで問題なく処理できると思います。

使用方法は非常に簡単です。回転させたい画像ビュー、ラジアン単位の回転、アニメーションの長さと画像ビューを渡すことで、以下に詳述するメソッドを呼び出すだけで、画像ビューは適切にアニメーション化されます。実際にはここで指定された方向があるため、常に「長い道のり」がかかります。

アニメーションに正の値を渡すと時計回りに回転し、負の値を指定すると反時計回りに回転します。

[self rotateView:imageView rotationInRadians:M_PI duration:2.0];


- (void)rotateView:(UIImageView *)imageView rotationInRadians:(CGFloat)radians duration:(CFTimeInterval)duration
{
    CABasicAnimation *rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];

    [rotationAnimation setToValue:[NSNumber numberWithFloat:radians]];
    [rotationAnimation setDuration:duration];
    [rotationAnimation setCumulative:YES];
    [rotationAnimation setFillMode:kCAFillModeForwards];
    [rotationAnimation setRemovedOnCompletion:NO];

    [imageView.layer addAnimation:rotationAnimation forKey:@"gaugeRotationAnimation"];
}
于 2013-08-09T23:53:52.910 に答える
3

私はしばらく前に同様の問題を抱えていました。私は 180 度だけ移動する必要がありましたが、時計回りに、時には反時計回りに必要な場合もありましたが、常に 2 つの間を行ったり来たりしていたため、コードの「回転」プロパティがありました。

CALayer と CAKeyframeAnimations を使用する必要があります。これが私のために働いたコードです。

-(void) showHideSpinnerWithDuration:(float) duration;
{
    CALayer* layer = _spinner.layer;
    CAKeyframeAnimation* animation;
    animation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"];

    animation.duration = duration;
    animation.cumulative = YES;
    animation.repeatCount = 1;
    animation.removedOnCompletion = NO;
    animation.fillMode = kCAFillModeForwards;

    if (_rotated) {
        animation.values = [NSArray arrayWithObjects:
                            [NSNumber numberWithFloat:DegreesToRadians(180)],
                            [NSNumber numberWithFloat:DegreesToRadians(0)],
                            nil];
        self.rotated = NO;
    } else {
        animation.values = [NSArray arrayWithObjects:
                            [NSNumber numberWithFloat:DegreesToRadians(0)],
                            [NSNumber numberWithFloat:DegreesToRadians(180)],
                            nil];
        self.rotated = YES;
    }

    animation.keyTimes = [NSArray arrayWithObjects:
                          [NSNumber numberWithFloat:0.0],
                          [NSNumber numberWithFloat:duration], nil];

    animation.timingFunctions = [NSArray arrayWithObjects:
                                 [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut],
                                 [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut], nil];

    [layer addAnimation:animation forKey:@"transform.rotation.z"];
}
于 2013-08-06T12:36:09.270 に答える
1

スイフト3

私はまったく同じ問題を抱えていました。これが他の誰かに役立つ場合の私の解決策です。

ポインターを含むレイヤーを参照します。

@IBOutlet weak var pointerImageView: UIImageView!

最後のポインター位置を追跡する変数を定義します。

private var meterPointerRadians: CGFloat = 0

パーセンテージを使用してメーター値を設定する関数を作成します。例: 50% の速度

func setMeter(dialPercentage: Double) {

    //define the start and end angles of your speed meter: Eg: from 90 to 180 (semi circle)
    let meterLowerRangeAngle: Double = 90.0 
    let meterUpperRangeAngle: Double = 180.0

    //calculate the angle of the pointer in radians
    let range = meterUpperRangeAngle - meterLowerRangeAngle
    let angle = (dialPercentage * range / 100) + meterLowerRangeAngle
    let radians: CGFloat = CGFloat(angle * .pi / 180)

    rotatePointer(imageView: self.pointerImageView, rotationInRadians: radians, duration: 1)

}

ポインタの最後の位置に応じて、時計回りまたは反時計回りにポインタを回転させます。

func rotatePointer(imageView: UIImageView, rotationInRadians: CGFloat, duration: CFTimeInterval) {

    let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation.z")

    rotationAnimation.fromValue = meterPointerRadians
    rotationAnimation.toValue = rotationInRadians
    rotationAnimation.duration = duration
    rotationAnimation.isCumulative = true
    rotationAnimation.fillMode = kCAFillModeBoth
    rotationAnimation.isRemovedOnCompletion = false

    imageView.layer.add(rotationAnimation, forKey: "pointerRotationAnimation")
    meterPointerRadians = CGFloat(rotationInRadians)

}
于 2017-05-18T22:39:10.197 に答える