iphone - 文字 - uiview animation repeat




-[CALayer setNeedsDisplayInRect:]の暗黙のアニメーションを無効にする (10)

-drawRect()メソッドを実装しているカスタムクラスにこれを追加します。 あなたのニーズに合わせてコードを変更してください。私にとっては、「不透明」がクロスフェードアニメーションを止めるトリックでした。

-(id<CAAction>) actionForLayer:(CALayer *)layer forKey:(NSString *)key
{
    NSLog(@"key: %@", key);
    if([key isEqualToString:@"opacity"])
    {
        return (id<CAAction>)[NSNull null];
    }

    return [super actionForLayer:layer forKey:key];
}

-drawInContext:メソッドに複雑な描画コードを含むレイヤーがあります。 私は必要な描画量を最小限にしようとしているので、変更された部分だけを更新するには-setNeedsDisplayInRect:を使用しています。 これは素晴らしく働いています。 しかし、グラフィックスシステムが自分のレイヤーを更新するとき、それはクロスフェードを使用して古い画像から新しい画像に移行しています。 私はそれを即座に切り替えることを望みます。

私は、CATransactionを使ってアクションを無効にし、期間をゼロに設定しようとしましたが、どちらも動作しませんでした。 使用しているコードは次のとおりです。

[CATransaction begin];
[CATransaction setDisableActions: YES];
[self setNeedsDisplayInRect: rect];
[CATransaction commit];

その代わりに私が使用すべきCATransactionに関する別のメソッドがありますか(私も-setValue:forKey:kCATransactionDisableActions、同じ結果を試しました)。


CATextLayerの文字列プロパティを変更するときに煩わしい(ぼやけた)アニメーションを無効にするには、次のようにします:

class CANullAction: CAAction {
    private static let CA_ANIMATION_CONTENTS = "contents"

    @objc
    func runActionForKey(event: String, object anObject: AnyObject, arguments dict: [NSObject : AnyObject]?) {
        // Do nothing.
    }
}

あなたのCATextLayerを適切に設定することを忘れないでください(正しいフォントなど)。

caTextLayer.actions = [CANullAction.CA_ANIMATION_CONTENTS: CANullAction()]

あなたはCATextLayerの私の完全なセットアップをここで見ることができます:

private let systemFont16 = UIFont.systemFontOfSize(16.0)

caTextLayer = CATextLayer()
caTextLayer.foregroundColor = UIColor.blackColor().CGColor
caTextLayer.font = CGFontCreateWithFontName(systemFont16.fontName)
caTextLayer.fontSize = systemFont16.pointSize
caTextLayer.alignmentMode = kCAAlignmentCenter
caTextLayer.drawsAsynchronously = false
caTextLayer.actions = [CANullAction.CA_ANIMATION_CONTENTS: CANullAction()]
caTextLayer.contentsScale = UIScreen.mainScreen().scale
caTextLayer.frame = CGRectMake(playbackTimeImage.layer.bounds.origin.x, ((playbackTimeImage.layer.bounds.height - playbackTimeLayer.fontSize) / 2), playbackTimeImage.layer.bounds.width, playbackTimeLayer.fontSize * 1.2)

uiImageTarget.layer.addSublayer(caTextLayer)
caTextLayer.string = "The text you want to display"

これでcaTextLayer.stringを必要なだけ更新できます=)

thisとthis答えに触発されました。


iOS 7では、これを行う便利な方法があります:

[UIView performWithoutAnimation:^{
    // apply changes
}];

Brad Larsonの回答に加えて、レイヤーのactionsディクショナリを変更するのではなく、カスタムレイヤー(あなたによって作成されたレイヤー)に対してデリゲートを使用することができます 。 このアプローチはより動的であり、より効果的である可能性があります。 また、すべてのアニメーション可能なキーを一覧表示することなく、すべての暗黙的なアニメーションを無効にすることができます。

残念ながら、カスタムUIViewデリゲートとしてUIViewを使用することは不可能です。これは、各UIViewがすでに独自のレイヤのデリゲートであるためです。 しかし、あなたはこのような簡単なヘルパークラスを使うことができます:

@interface MyLayerDelegate : NSObject
    @property (nonatomic, assign) BOOL disableImplicitAnimations;
@end

@implementation MyLayerDelegate

- (id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event
{
    if (self.disableImplicitAnimations)
         return (id)[NSNull null]; // disable all implicit animations
    else return nil; // allow implicit animations

    // you can also test specific key names; for example, to disable bounds animation:
    // if ([event isEqualToString:@"bounds"]) return (id)[NSNull null];
}

@end

使用法(ビュー内):

MyLayerDelegate *delegate = [[MyLayerDelegate alloc] init];

// assign to a strong property, because CALayer's "delegate" property is weak
self.myLayerDelegate = delegate;

self.myLayer = [CALayer layer];
self.myLayer.delegate = delegate;

// ...

self.myLayerDelegate.disableImplicitAnimations = YES;
self.myLayer.position = (CGPoint){.x = 10, .y = 42}; // will not animate

// ...

self.myLayerDelegate.disableImplicitAnimations = NO;
self.myLayer.position = (CGPoint){.x = 0, .y = 0}; // will animate

ビューのカスタムサブレイヤのデリゲートとしてビューのコントローラを持つと便利なことがあります。 この場合、ヘルパークラスは必要ありません。コントローラー内にactionForLayer:forKey:メソッドを実装することができます。

重要な注意: UIViewの下層のデリゲートを変更しないでください(暗黙のアニメーションを有効にするなど) - 悪いことが起こります:)

注:レイヤーの再描画をアニメーション化する(アニメーションを無効にしない)場合は、実際の再描画が後で行われる可能性があるため、 [CALayer setNeedsDisplayInRect:] callを[CALayer setNeedsDisplayInRect:]に配置することは無意味です。 良い答え、この答えで説明さているよう 、カスタムプロパティを使用することです。


ここでは、受け入れられた答えに似ていますが、 Swiftにとってより効率的な解決法があります。 場合によっては、パフォーマンスに関する懸案事項である値を変更するたびにトランザクションを作成するほうがよいでしょう。例えば、レイヤーの位置を60fpsでドラッグする一般的な使用例です。

// Disable implicit position animation.
layer.actions = ["position": NSNull()]      

レイヤーアクションがどのように解決されるについては、appleのドキュメントを参照してください。 デリゲートを実装すると、カスケードでさらに1つのレベルがスキップされますが、私のケースでは、関連付けられたUIViewに設定する必要があるデリゲートについての注意点のため、あまりにも面倒です。

編集: NSNull準拠していることを指摘してNSNullたコメント担当者に感謝します。


これを行うには、レイヤーのアクション辞書を設定して、 [NSNull null]を適切なキーのアニメーションとして返すようにします。 たとえば、私は

NSDictionary *newActions = @{
    @"onOrderIn": [NSNull null],
    @"onOrderOut": [NSNull null],
    @"sublayers": [NSNull null],
    @"contents": [NSNull null],
    @"bounds": [NSNull null]
};

layer.actions = newActions;

レイヤーのサイズや内容の変更だけでなく、レイヤー内のサブレイヤーの挿入や変更時にフェードイン/アウトアニメーションを無効にすることもできます。 更新された図面のクロスフェードを防ぐために、 contentsキーがあなたが探しているものだと私は信じています。


また、

[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];

//foo

[CATransaction commit];

サムの答えとSimonの困難に基づいて... CSShapeLayerを作成した後にデリゲートリファレンスを追加する:

CAShapeLayer *myLayer = [CAShapeLayer layer];
myLayer.delegate = self; // <- set delegate here, it's magic.

... "m"ファイルのどこかに...

基本的にSamと同じですが、カスタムの "disableImplicitAnimations"変数の配列を切り替えることはできません。 "ハードワイヤー"アプローチの詳細

- (id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event {

    // disable all implicit animations
    return (id)[NSNull null];

    // allow implicit animations
    // return nil;

    // you can also test specific key names; for example, to disable bounds animation:
    // if ([event isEqualToString:@"bounds"]) return (id)[NSNull null];

}

内部的にsetValue:forKey:を呼び出すCATransaction内部のアクションを無効にする簡単な方法を見つけましたkCATransactionDisableActionsキーの場合:

[CATransaction setDisableActions:YES];

迅速:

CATransaction.setDisableActions(true)

実際には、私は正しい答えではありませんでした。 私の問題を解決する方法はこれでした:

- (id<CAAction>)actionForKey:(NSString *)event {   
    return nil;   
}

特定のアニメーションを無効にするには、その中のロジックを自由にすることができますが、それらをすべて削除したいので、ゼロを返しました。





calayer