2

OK、私はここSOのさまざまな投稿に基づいてこれを行う方法を理解しました、そしてそれは素晴らしい働きをします。私は、小さな領域を除いて基本的にウィンドウ全体をマスクするオーバーレイに取り組んでいます。これは、私のアプリの特定の領域に注意を引くためのものです。私はたくさんの呼び出しを使用していますmoveToPoint:addLineToPoint:これは私のCALayerサブクラスにあります' drawInContext:):

....

// inner path (CW)
[holePath moveToPoint:CGPointMake(x, y)];
[holePath addLineToPoint:CGPointMake(x + w, y)];
[holePath addLineToPoint:CGPointMake(x + w, y + h)];
[holePath addLineToPoint:CGPointMake(x, y+h)];

// outer path (CCW)
[holePath moveToPoint:CGPointMake(xBounds, yBounds)];
[holePath addLineToPoint:CGPointMake(xBounds, yBounds + hBounds)];
[holePath addLineToPoint:CGPointMake(xBounds + wBounds, yBounds + hBounds)];
[holePath addLineToPoint:CGPointMake(xBounds + wBounds, yBounds)];

// put the path in the context
CGContextBeginPath(ctx);
CGContextMoveToPoint(ctx, 0, 0);
CGContextAddPath(ctx, holePath.CGPath);
CGContextClosePath(ctx);

// set the color
CGContextSetFillColorWithColor(ctx, self.overlayColor.CGColor);

// draw the overlay
CGContextDrawPath(ctx, kCGPathFillStroke);

holePathのインスタンスですUIBezierPath。)

ここまでは順調ですね。次のステップはアニメーションです。これを行うために(私はここSOでもこのテクニックを見つけました)私は次のような方法を作りました

-(CABasicAnimation *)makeAnimationForKey:(NSString *)key {
    CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:key];
    anim.fromValue = [[self presentationLayer] valueForKey:key];
    anim.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    anim.duration = 0.5;

    return anim;
}

actionForKey:initWithLayer:および( inneedsDisplayForKey:の結果を返します。これで、暗黙のCAAnimationsを使用してアニメーション化できるプロパティを持つ素敵な「穴レイヤー」が得られます!残念ながら、それは非常に途切れ途切れです。1秒あたり2または3フレームのようなものが得られます。おそらく問題は背景にあると思い、それをスナップショットに置き換えようとしましたが、サイコロはありませんでした。次に、Instrumentsを使用してプロファイルを作成し、ここでの巨大な豚がへの呼び出しであることを発見しました。makeAnimationForKey:actionForKey:holeRectCGContextDrawPath()

tl; dr私の質問はこれに帰着すると思います:より速く再描画される穴のあるこのレイヤーを作成するより簡単な方法はありますか?私の勘は、使用しているパスを単純化できれば、パスの描画が軽くなるということです。またはおそらくマスキング?助けてください!

4

4 に答える 4

3

わかりました、私はphix23の提案を試しました、そしてそれは完全にトリックをしました!最初はサブクラスCALayer化してサブレイヤーとして追加してCAShapeLayerいましたが、正しく動作させることができず、この時点でかなり疲れていたので、あきらめてサブクラスを完全にCAShapeLayer!に置き換えました。上記のコードを独自のメソッドで使用し、を返し、UIBezierPath次のようにアニメーション化しました。

UIBezierPath* oldPath = [self pathForHoleRect:self.holeRect];
UIBezierPath* newPath = [self pathForHoleRect:rectToHighlight];
self.holeRect = rectToHighlight;

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"path"];
animation.duration = 0.5;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
animation.fromValue = (id)oldPath.CGPath;
animation.toValue = (id)newPath.CGPath;
[self.holeLayer addAnimation:animation forKey:@"animatePath"];
self.holeLayer.path = newPath.CGPath;

興味深いサイドノート-path暗黙的にアニメート可能ではありません。それは理にかなっていると思います。

于 2012-11-05T06:45:21.680 に答える
2

再描画には費用がかかりますが、アニメーションには費用がかかりません。「holeRect」の値を設定すると、レイヤー全体に再描画するように指示されます。これは、典型的なパフォーマンスの最適化されたプロパティアニメーションと同じではありません。レイヤーが画面全体のサイズである場合、すべてのフレームでレイヤーの新しいバージョンを効果的に再作成しています。これは、スムーズなアニメーションを保証するためにアップルが行うことの1つです。再描画をできるだけ防止したい。

中央に穴のあるレイヤーを作成し、穴が中央にある場合でも、レイヤーが画面全体をカバーするのに十分な大きさであることを確認することをお勧めします。次に、アニメーションはレイヤーの「位置」プロパティをアニメーション化する必要があります。この巨大なレイヤーを一度に使用するのは無駄に思えるかもしれませんが、すべてのフレームで再描画するよりもはるかに無駄が少なくなります。「holeRect」インターフェースを維持したい場合は可能ですが、「holeRect」プロパティを持つレイヤーには、(drawInContextではなくlayoutSubviewsで)説明した方法でアニメーション化された1つまたは複数のサブレイヤーが含まれている必要があります。

要約すると、位置、不透明度をアニメートしていることを確認し、これらはレイヤー上で最も効率的なアニメーションの1つであるため変換し、必要な場合にのみ再描画します。

于 2012-11-05T03:32:35.767 に答える
0

あなたの例では、長方形の穴を使用します。このようなアニメーションの実装は、4つの長方形のレイヤーを使用する場合により効率的になる可能性があります(添付の画像を参照)。穴の長方形の位置をアニメートするには、青いレイヤーの幅と赤いレイヤーの高さをアニメートする必要があります。(穴の長方形が幅を変更できる場合は、赤いレイヤーの幅もアニメーション化する必要があります)

非長方形の穴が必要な場合は、これらの中央に別のレイヤーを配置します。このレイヤーには穴があり、このレイヤーの位置のみを変更します(2番目の画像を参照)。この非長方形の穴のサイズを変更すると、中間レイヤーのコンテンツのみが再作成されるため、正しく理解すれば、このレイヤーが画面のサイズであった元のケースよりも少し速くなるはずです。

多層アプローチ 多層アプローチ、非長方形の穴

于 2012-11-05T05:00:31.587 に答える
-1

評判のために(まだ)あなたの質問にコメントすることができないので、私は回答を投稿しています。

私の質問は、これをプログラムで作成する必要があるかどうかです。アテンションエリアを作成するだけの場合は、別のアプローチを使用できます。

透明な穴のある黒いpngを使用してみませんか?そうすれば、アニメーション中にパフォーマンスの問題が発生することはなく、元の穴のサイズを適切に選択すれば、サイズを変更することもできます。画像は、穴の現在の位置とは無関係にビューのすべての部分をカバーするのに十分な大きさである必要があります。穴の外側の部分にも透明度が含まれている可能性があり、注意領域の外側に影の効果が生じます。

于 2012-10-31T08:22:43.347 に答える