Вопрос по caanimation, ios, iphone, calayer, animation – Как удалить слой после его анимации?

2

Я делаюiOS-приложение, У меня есть несколькоCALayer объекты, которые в конечном итоге будутудаленный (сокращается)анимация, Когда анимация завершена, иanimationDidStop:finished вызывается, я хотел быУдалить CALayer объект изсупер вид и удали его.

Но как я могу получитьCALayer объект вanimationDidStop:finished? Я бы догадался, чтоCAanimation-объект имел указатель на слой, но я могуне найти его в док.Есть ли лучший способ решить проблему? (На самом деле, у меня есть несколько объектов анимации, добавленных к одному слою, и, в идеале, я хотел бы удалить слой только после завершения последней анимации)

Ваш Ответ

4   ответа
0

Выполните действие после завершения анимации Я считаю, что animateWithDuration: animations: creation: намного проще в использовании, чем работа непосредственно с CALayer. Вы можете связать несколько анимаций через обработчик завершения, а затем удалить слой из последнего. например:

[UIView animateWithDuration:1.0 animations:^{
    // do first animation in the sequence
} completion:^(BOOL finished) {
    [UIView animateWithDuration:1.0 animations:^{
        // do second animation in the sequence
    } completion:^(BOOL finished) {
        [UIView animateWithDuration:1.0 animations:^{
            // do third animation in the sequence
        } completion:^(BOOL finished) {
            // remove layer after all are done
        }];
    }];
}];

Возможно, это немного запутанно, но вы можете, например, преобразовать их в их собственные вызовы методов.

Я не уверен, как использоватьблоки оживитьCALayer объекты (в ioS5 или 6). ragnarius
0

бъекту анимации.словарь, как следует

// in some define section
#define kAnimationRemoveLayer @"animationRemoveLayer"

затем в animationDidStop

- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag{
    CALayer *lay = [theAnimation valueForKey:kAnimationRemoveLayer];
    if(lay){
        [lay removeAllAnimations];
        [lay removeFromSuperlayer];
    }
}

и, наконец, в настройке анимации,

CALAyer * lay = ... ;
BOOL    shouldRemove = .... ; 
CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:@"position"];
anim.delegate = self;
if (shouldRemove)
    [anim setValue:lay forKey:kAnimationRemoveLayer];
1

просто передайте CALayer, который вы хотите удалить с вашей анимацией.

Что касается удаления всех анимаций, у вас есть два варианта:

Вы можете проверить свой CALayer 's animationKeys для любых существующих анимаций.Вы можете использовать CAAnimationGroup и сгруппировать все ваши анимации вместе.
Я призываюaddAnimation: forKey:Как я могу передать объект CALayer? ragnarius
Я опубликовал альтернативное решение, но я проверяю ваше решение как ответ! ragnarius
Так ты имеешь в виду, чтоanimationDidStop: закончил: следует ли сканировать этот изменяемый массив, чтобы увидеть, сможет ли он найти объекты слоя, у которых нет текущих анимаций, а затем удалить их как из массива, так и из суперслоя? ragnarius
Да, или если все ваши анимации находятся на одном CALayer, вы можете пропустить NSMutableArray. CAAnimations довольно низкого уровня. Они нене беру машину много другого, кроме анимации. Вот почему блочная анимация UIView более распространена. Patrick Tescher
Вы можете иметь свойство NSMutableArray в вашем делегате. Каждый раз, когда вы используете addAnimation: forKey: добавьте этот CALayer в NSMutableArray. Затем вы можете ссылаться на все CALayers от вашего делегата. Patrick Tescher
2

Прошло много времени с тех пор, как на этот вопрос был дан ответ, однако япостараюсь добавить ещеSwifty решение, в случае, если кто-то все еще ищет более чистое решение в настоящее время.

Если все, что выВы просто можете удалить слой, как только CAAnimation завершится, вы можете назначить анимацию 's делегировать простой объект NSObject, который содержит ссылку на целевой слой и ожидает обратного вызова анимации, чтобы отклонить его.

Позволять'вызовите этот вспомогательный объектLayerRemover:

class LayerRemover: NSObject, CAAnimationDelegate {
    private weak var layer: CALayer?

    init(for layer: CALayer) {
        self.layer = layer
        super.init()
    }

    func animationDidStop(_ anim: CAAnimation, finished flag: Bool) {
        layer?.removeFromSuperlayer()
    }
}

Все, что этот объект делает, получает ссылку CALayer через инициализатор и ждет обратного вызова animationDidStop перед удалением слоя. На данный момент, как только CAAnimation, чтоПри сохранении его через свойство делегата деинициализируется, а также удаляется средство удаления слоев.

Теперь все, что вам нужно сделать, это на самом деле установить этот съемник и использовать его:

let layer = CAShapeLayer()
layer.path = UIBezierPath(ovalIn: CGRect(x: 0, y: 0, width: 200, height: 100)).cgPath
let myAnimation = CABasicAnimation(keyPath: "strokeEnd")
...
myAnimation.delegate = LayerRemover(for: layer)

Тот'сидеть!

Обратите внимание, что вы ненеобходимо сохранить любую ссылку на объект LayerRemover, так как изДокументация Apple мы можем прочитать это

Объект делегата сохраняется получателем. Это редкое исключение из правил управления памятью, описанных в Руководстве по программированию Advanced Memory Management.

Тот'действительно чистое решение, намного лучше, чем отслеживание каждой анимации вanimationDidStop(:finished:), Спасибо!🙂 Pomme2Poule
Люблю это решение! Также оцените дополнительное внимание к деталям, касающимся управления памятью. DanielGibbs

Похожие вопросы