17

CALayerの境界をどのようにアニメーション化できるのか疑問に思っているので、境界が変わるたびに、レイヤーはを呼び出しますdrawInContext:。CALayerサブクラスで次の2つのメソッドを試しました。

  • needsDisplayOnBoundsChangeに設定YES
  • キーYESの+(BOOL)needsDisplayForKey:(NSString*)keyを返すbounds

どちらも機能しません。CALayerは、レイヤーの元のコンテンツを使用し、それに応じて単純にスケーリングすることを決定しているようですcontentsGravity(これは、パフォーマンスのためだと思います)。これに対する回避策ですか、それとも明らかな何かが欠けていますか?

編集:そして、ちなみに、私のカスタムサブクラスが-奇妙なものを作成するためにCALayer呼び出していないことに気づきました。initWithLayer:presentationLayer

よろしくお願いします、サム

4

5 に答える 5

7

ここで概説されている手法を使用できます。CALayer の+needsDisplayForKey:メソッドをオーバーライドすると、アニメーションのすべてのステップでコンテンツが再描画されます。

于 2011-10-31T02:51:17.473 に答える
1

viewFlags の設定が効果的かどうかはわかりません。2 番目の解決策は確実に機能しません。

デフォルトの実装は NO を返します。サブクラスは、スーパークラスによって定義されたプロパティに対して * super を呼び出す必要があります。(たとえば、* CALayer によって実装されたプロパティに対して YES を返そうとしないでください。* 実行すると、未定義の結果が生じます。)

ビューのコンテンツ モードを UIViewContentModeRedraw に設定する必要があります。

UIViewContentModeRedraw,    //redraw on bounds change (calls -setNeedsDisplay)

CALayer を使用したコンテンツの提供に関する Apple のドキュメントを確認してください。彼らは、サブクラスの代わりに CALayer のデリゲート プロパティを使用することを推奨しています。

于 2011-10-31T01:52:48.103 に答える
0

これがあなたの質問に対する解決策として完全に適格かどうかはわかりませんが、これを機能させることができました.

最初に、コンテンツ イメージをCGImageRef.

次に-display、レイヤーINSTEAD OF -drawInContext:のメソッドをオーバーライドしました。contentsその中で、事前にレンダリングされたCGImageに設定しましたが、うまくいきました。

最後に、コンテンツの画像が拡大縮小され contentsGravityないように、レイヤーのデフォルトを変更する必要があります。@"left"

私が抱えていた問題は、渡されるコンテキストが-drawInContext:レイヤーの開始サイズであり、アニメーション後の最終サイズではないことでした。(これはCGBitmapContextGetWidthおよびCGBitmapContextGetHeightメソッドで確認できます。)

私のメソッドは、アニメーション全体で 1 回しか呼び出されませんが、レイヤーのコンテンツを-displayメソッドで直接設定すると、可視境界よりも大きな画像を渡すことができます。drawInContext:CGContext コンテキストの境界外に描画できないため、メソッドはこれを許可しません。

レイヤーの描画方法の違いについて詳しくは、http://www.apeth.com/iOSBook/ch16.htmlを参照してください。

于 2015-11-05T04:56:04.040 に答える
0

私は最近同じ問題に直面しています。これは私が見つけたものです:

あなたがそれを行うことができるトリックがあります。それは、次のような境界のシャドウコピーをアニメーション化することです:

var shadowBounds: CGRect {
  get { return bounds }
  set { bounds = newValue}
}

次に、CALayer の +needsDisplayForKey: をオーバーライドします。

ただし、描画が境界に依存している場合、これはやりたいことではないかもしれません。既にお気づきのように、コア アニメーションは単にレイヤーのコンテンツをスケーリングして境界をアニメーション化します。これは、上記のトリックを行った場合でも当てはまります。つまり、アニメーション中に境界が変更された場合でも、コンテンツはスケーリングされます。その結果、描画のアニメーションに一貫性がなくなります。

それを解決する方法は?コンテンツはスケーリングされるため、逆スケーリングすることで描画を決定するカスタム変数の値を計算して、スケーリングされた最終的なコンテンツの描画が元のスケーリングされていないものと同じに見えるようにし、fromValues をこれらの値に設定できます。 toValues を古い値に変更し、境界を指定して同時にアニメーション化します。最終値を変更する場合は、toValues をこれらの最終値に設定します。再描画を行うには、少なくとも 1 つのカスタム変数をアニメーション化する必要があります。

于 2017-07-16T04:58:09.120 に答える
-2

これはカスタム クラスです。

@implementation MyLayer

-(id)init
{
    self = [super init];
    if (self != nil)
        self.actions = [NSDictionary dictionaryWithObjectsAndKeys:
                        [NSNull null], @"bounds",
                        nil];
    return self;
}

-(void)drawInContext:(CGContextRef)context
{
    CGContextSetRGBFillColor(context,
                             drand48(),
                             drand48(),
                             drand48(),
                             1);
    CGContextFillRect(context,
                      CGContextGetClipBoundingBox(context));
}

+(BOOL)needsDisplayForKey:(NSString*)key
{
    if ([key isEqualToString:@"bounds"])
        return YES;
    return [super needsDisplayForKey:key];
}

@end

これらは、xcode 4.2 デフォルト テンプレートへの追加です。

-(BOOL)application:(UIApplication*)application
didFinishLaunchingWithOptions:(NSDictionary*)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        // Override point for customization after application launch.
    self.window.backgroundColor = [UIColor whiteColor];
    [self.window makeKeyAndVisible];

        // create and add layer
    MyLayer *layer = [MyLayer layer];
    [self.window.layer addSublayer:layer];
    [self performSelector:@selector(changeBounds:)
               withObject:layer];

    return YES;
}

-(void)changeBounds:(MyLayer*)layer
{
        // change bounds
    layer.bounds = CGRectMake(0, 0,
                              drand48() * CGRectGetWidth(self.window.bounds),
                              drand48() * CGRectGetHeight(self.window.bounds));

        // call "when idle"
    [self performSelector:@selector(changeBounds:)
               withObject:layer
               afterDelay:0];
}

----------------- 編集:

わかりました...これはあなたが求めたものではありません:)ごめんなさい:|

----------------- 編集済み(2):

そして、なぜそのようなものが必要なのですか?(void)display使用できますが、ドキュメントには設定用にあると記載されていますself.contents...

于 2011-11-01T22:59:16.603 に答える