119

iOSで(QuadCurve)CALayerに沿って非常にうまくアニメーション化しています。しかし、Appleが提供するいくつかのイージング関数 (EaseIn/EaseOut など)CGPathよりも興味深いイージング関数を使用したいと考えています。たとえば、跳ね返りや弾性関数です。

MediaTimingFunction (ベジエ) を使用すると、次のことが可能です。

ここに画像の説明を入力

しかし、もっと複雑なタイミング関数を作成したいと考えています。問題は、メディア タイミングがこれらの効果を作成するのに十分強力ではない 3 次ベジエを必要とするように見えることです。

ここに画像の説明を入力
(出典: sparrow-framework.org )

上記を作成するためのコードは、他のフレームワークでは十分に単純であるため、これは非常にイライラさせられます。曲線は入力時間を出力時間 (Tt 曲線) にマッピングしており、時間-位置曲線ではないことに注意してください。たとえば、easyOutBounce(T) = tは新しいtを返します。次に、そのtを使用して動き (またはアニメーション化する必要のあるプロパティ) をプロットします。

それで、複雑なカスタムを作成したいのCAMediaTimingFunctionですが、それを行う方法がわからない、または可能かどうかさえわかりません。代替手段はありますか?

編集:

手順の具体例を次に示します。非常に教育的:)

  1. ポイントaからbまでの線に沿ってオブジェクトをアニメートしたいのですが、上記のeasyOutBounce曲線を使用して線に沿ってその動きを「バウンス」させたいです。これは、 a から b までの正確なラインをたどりますが現在ベジエ ベースの CAMediaTimingFunction を使用して可能な方法よりも複雑な方法で加速および減速することを意味します。

  2. その線をCGPathで指定した任意の曲線移動にしましょう。その曲線に沿って移動する必要がありますが、直線の例と同じように加速および減速する必要があります。

理論的には、次のように動作するはずだと思います。

移動曲線をキーフレーム アニメーションmove(t) = pとして記述します。ここで、tは時間 [0..1]、pは時間tで計算された位置です。したがって、move(0)は曲線の始点の位置を返し、move(0.5)は正確な中央を返し、 move(1)は終点を返します。タイミング関数time(T) = tを使用して移動のt値を提供すると、私が望むものが得られるはずです。バウンス効果の場合、タイミング関数はtime(0.8)time(0.8 ) に対して同じt値を返す必要があります。(ほんの一例)。タイミング関数を置き換えるだけで、別の効果が得られます。

(はい、前後に移動する 4 つの線分を作成して結合することにより、ライン バウンスを行うことができますが、それは必要ではありません。結局のところ、時間値を位置にマッピングする単純な線形関数にすぎません。)

ここで意味を成していることを願っています。

4

6 に答える 6

48

私はこれを見つけました:

Cocoa with Love - Core Animation のパラメトリック加速曲線

しかし、ブロックを使用することで、もう少しシンプルで読みやすくすることができると思います。したがって、次のような CAKeyframeAnimation のカテゴリを定義できます。

CAKeyframeAnimation+Parametric.h:

// this should be a function that takes a time value between 
//  0.0 and 1.0 (where 0.0 is the beginning of the animation
//  and 1.0 is the end) and returns a scale factor where 0.0
//  would produce the starting value and 1.0 would produce the
//  ending value
typedef double (^KeyframeParametricBlock)(double);

@interface CAKeyframeAnimation (Parametric)

+ (id)animationWithKeyPath:(NSString *)path 
      function:(KeyframeParametricBlock)block
      fromValue:(double)fromValue
      toValue:(double)toValue;

CAKeyframeAnimation+Parametric.m:

@implementation CAKeyframeAnimation (Parametric)

+ (id)animationWithKeyPath:(NSString *)path 
      function:(KeyframeParametricBlock)block
      fromValue:(double)fromValue
      toValue:(double)toValue {
  // get a keyframe animation to set up
  CAKeyframeAnimation *animation = 
    [CAKeyframeAnimation animationWithKeyPath:path];
  // break the time into steps
  //  (the more steps, the smoother the animation)
  NSUInteger steps = 100;
  NSMutableArray *values = [NSMutableArray arrayWithCapacity:steps];
  double time = 0.0;
  double timeStep = 1.0 / (double)(steps - 1);
  for(NSUInteger i = 0; i < steps; i++) {
    double value = fromValue + (block(time) * (toValue - fromValue));
    [values addObject:[NSNumber numberWithDouble:value]];
    time += timeStep;
  }
  // we want linear animation between keyframes, with equal time steps
  animation.calculationMode = kCAAnimationLinear;
  // set keyframes and we're done
  [animation setValues:values];
  return(animation);
}

@end

使用法は次のようになります。

// define a parametric function
KeyframeParametricBlock function = ^double(double time) {
  return(1.0 - pow((1.0 - time), 2.0));
};

if (layer) {
  [CATransaction begin];
    [CATransaction 
      setValue:[NSNumber numberWithFloat:2.5]
      forKey:kCATransactionAnimationDuration];

    // make an animation
    CAAnimation *drop = [CAKeyframeAnimation 
      animationWithKeyPath:@"position.y"
      function:function fromValue:30.0 toValue:450.0];
    // use it
    [layer addAnimation:drop forKey:@"position"];

  [CATransaction commit];
}

あなたが望んでいたほど単純ではないかもしれませんが、それは始まりです。

于 2011-05-11T01:51:15.147 に答える
36

iOS 10 から、2 つの新しいタイミング オブジェクトを使用してカスタム タイミング関数を簡単に作成できるようになりました。

1) UICubicTimingParametersにより、3 次ベジエ曲線をイージング関数として定義できます。

let cubicTimingParameters = UICubicTimingParameters(controlPoint1: CGPoint(x: 0.25, y: 0.1), controlPoint2: CGPoint(x: 0.25, y: 1))
let animator = UIViewPropertyAnimator(duration: 0.3, timingParameters: cubicTimingParameters)

または単にアニメーターの初期化で制御点を使用する

let controlPoint1 = CGPoint(x: 0.25, y: 0.1)
let controlPoint2 = CGPoint(x: 0.25, y: 1)
let animator = UIViewPropertyAnimator(duration: 0.3, controlPoint1: controlPoint1, controlPoint2: controlPoint2) 

この素晴らしいサービスは、曲線のコントロール ポイントを選択するのに役立ちます。

2) UISpringTimingParametersを使用すると、開発者は減衰比質量剛性、および初期速度を操作して、目的のスプリング動作を作成できます。

let velocity = CGVector(dx: 1, dy: 0)
let springParameters = UISpringTimingParameters(mass: 1.8, stiffness: 330, damping: 33, initialVelocity: velocity)
let springAnimator = UIViewPropertyAnimator(duration: 0.0, timingParameters: springParameters)

Duration パラメータは引き続き Animator に表示されますが、春のタイミングでは無視されます。

これら 2 つのオプションでは不十分な場合は、UITimingCurveProviderプロトコルを確認することで、独自のタイミング カーブを実装することもできます。

詳細、異なるタイミング パラメータでアニメーションを作成する方法については、ドキュメントを参照してください。

また、 WWDC 2016 の UIKit アニメーションとトランジションのプレゼンテーションの進歩もご覧ください。

于 2016-11-01T15:48:29.870 に答える
14

カスタム タイミング関数を作成する方法は、CAMediaTimingFunction の functionWithControlPoints:::: ファクトリ メソッドを使用することです (対応する initWithControlPoints:::: init メソッドもあります)。これにより、タイミング関数のベジエ曲線が作成されます。これは任意の曲線ではありませんが、ベジエ曲線は非常に強力で柔軟です。コントロール ポイントのコツをつかむには、少し練習が必要です。ヒント: ほとんどの描画プログラムでベジエ曲線を作成できます。それらをいじると、コントロール ポイントで表現している曲線に関する視覚的なフィードバックが得られます。

このリンクは、アップルのドキュメントを指しています。プリビルド関数が曲線からどのように構築されるかについての短いが役に立つセクションがあります。

編集: 次のコードは、単純なバウンス アニメーションを示しています。そのために、構成されたタイミング関数 (タイミングNSArray プロパティ) を作成し、アニメーションの各セグメントに異なる時間の長さ ( keytimesプロパティ) を与えました。このようにして、ベジエ曲線を構成して、アニメーションのより洗練されたタイミングを構成できます。これは、このタイプのアニメーションに関する良い記事で、素敵なサンプル コードが含まれています。

- (void)viewDidLoad {
    UIView *v = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 50.0, 50.0)];

    v.backgroundColor = [UIColor redColor];
    CGFloat y = self.view.bounds.size.height;
    v.center = CGPointMake(self.view.bounds.size.width/2.0, 50.0/2.0);
    [self.view addSubview:v];

    //[CATransaction begin];

    CAKeyframeAnimation * animation; 
    animation = [CAKeyframeAnimation animationWithKeyPath:@"position.y"]; 
    animation.duration = 3.0; 
    animation.removedOnCompletion = NO;
    animation.fillMode = kCAFillModeForwards;

    NSMutableArray *values = [NSMutableArray array];
    NSMutableArray *timings = [NSMutableArray array];
    NSMutableArray *keytimes = [NSMutableArray array];

    //Start
    [values addObject:[NSNumber numberWithFloat:25.0]];
    [timings addObject:GetTiming(kCAMediaTimingFunctionEaseIn)];
    [keytimes addObject:[NSNumber numberWithFloat:0.0]];


    //Drop down
    [values addObject:[NSNumber numberWithFloat:y]];
    [timings addObject:GetTiming(kCAMediaTimingFunctionEaseOut)];
    [keytimes addObject:[NSNumber numberWithFloat:0.6]];


    // bounce up
    [values addObject:[NSNumber numberWithFloat:0.7 * y]];
    [timings addObject:GetTiming(kCAMediaTimingFunctionEaseIn)];
    [keytimes addObject:[NSNumber numberWithFloat:0.8]];


    // fihish down
    [values addObject:[NSNumber numberWithFloat:y]];
    [keytimes addObject:[NSNumber numberWithFloat:1.0]];
    //[timings addObject:GetTiming(kCAMediaTimingFunctionEaseIn)];



    animation.values = values;
    animation.timingFunctions = timings;
    animation.keyTimes = keytimes;

    [v.layer addAnimation:animation forKey:nil];   

    //[CATransaction commit];

}
于 2011-03-01T23:15:28.937 に答える
10

まだ探しているかどうかはわかりませんが、PRTweenは、Core Animation がすぐに提供するもの、特にカスタム タイミング関数を超える能力という点でかなり印象的です。また、さまざまな Web フレームワークが提供する一般的なイージング カーブのすべてではないにしても、多くがパッケージ化されています。

于 2012-10-17T20:43:35.030 に答える