Как отключить неявные анимации CALayer?
Это сводит меня с ума! Я работаю над графическим приложением. Скажем, я работаю над таблицей UIView
.
Я добавляю некоторые подслои к этому представлению ([sheet.layer addSublayer:...]
), а затем я хочу рисовать их. Для этого я создаю CGImageRef
и помещаю его в слой contents
. Но он оживился, и я не хочу этого.
Я пробовал все:
-
removeAnimationForKey:
-
removeAllAnimations
- установить словарь действий
- с помощью actionlayer
delegate
-
[CATransaction setDisableAnimations:YES]
Кажется правильным. Я не понимаю, почему этот слой все еще анимирован; _;
Я делаю что-то неправильно? Есть ли секретный способ?
Ответы
Ответ 1
Вы должны явно отключить анимацию, обернув свой код в CATransaction
[CATransaction begin];
[CATransaction setValue:(id)kCFBooleanTrue
forKey:kCATransactionDisableActions];
layer.content = someImageRef;
[CATransaction commit];
Ответ 2
Swift
CATransaction.begin()
CATransaction.setDisableActions(true)
// change layer properties that you don't want to animate
CATransaction.commit()
Ответ 3
Как и в Mac OS X 10.6 и iOS 3, CATransaction
также имеет метод setDisableActions
, который устанавливает значение для клавиши kCATransactionDisableActions
.
[CATransaction begin];
[CATransaction setDisableActions:YES];
layer.content = someImageRef;
[CATransaction commit];
В Swift мне нравится использовать этот метод расширения:
extension CATransaction {
class func withDisabledActions<T>(_ body: () throws -> T) rethrows -> T {
CATransaction.begin()
CATransaction.setDisableActions(true)
defer {
CATransaction.commit()
}
return try body()
}
}
Затем вы можете использовать его следующим образом:
CATransaction.withDisabledActions {
// your stuff here
}
Ответ 4
Другой способ:
-
Вы должны отключить анимацию по умолчанию вашего листового слоя, который неявно называется добавлением подуровня.
-
Вы также должны использовать контент-анимацию каждого подуровня. Конечно, вы можете использовать "kCATransactionDisableActions" CATransaction каждый раз, когда вы устанавливаете sublayer.content. Но вы можете отключить эту анимацию один раз, когда вы создаете подуровень.
Вот код:
// disable animation of container
sheet.layer.actions = [NSDictionary dictionaryWithObject:[NSNull null]
forKey:@"sublayers"];
// disable animation of each sublayer
sublayer.layer.actions = [NSDictionary dictionaryWithObject:[NSNull null]
forKey:@"content"];
// maybe, you'll also have to disable "onOrderIn"-action of each sublayer.
Ответ 5
Swift 2
Мне удалось отключить все анимации следующим образом, где myView
- это вид, с которым вы работаете:
myView.layer.sublayers?.forEach { $0.removeAllAnimations() }
И как примечание, удалив все слои:
myView.layer.sublayers?.forEach { $0.removeFromSuperlayer() }
Ответ 6
Многоразовый глобальный код:
/**
* Disable Implicit animation
* EXAMPLE: disableAnim{view.layer?.position = 20}//Default animation is now disabled
*/
func disableAnim(_ closure:()->Void){
CATransaction.begin()
CATransaction.setDisableActions(true)
closure()
CATransaction.commit()
}
Добавьте этот код в любом месте вашего кода (в глобальном масштабе)
Ответ 7
Расширение Swift 4:
extension CATransaction {
static func disableAnimations(_ completion: () -> Void) {
CATransaction.begin()
CATransaction.setDisableActions(true)
completion()
CATransaction.commit()
}
}
Использование:
CATransaction.disableAnimations {
// things you don't want to animate
}
Ответ 8
перед добавлением слоя к вашему виду с помощью [self.layer addSublayer:yourCALayer]
а также после того, как он уже добавлен, вы можете отключить определенные анимированные свойства вашего CALayer, переписав ключ анимации. Ключ, который вы установили в NULL, назван в честь свойства, здесь показано, как это сделано для layer.position = CGPoint(x,y);
yourCALayer.actions = [NSDictionary dictionaryWithObject:[NSNull null] forKey:@"position"];
Поскольку свойство actions
- это NSDictionary, который не позволяет хранить nil
вы устанавливаете его явным образом для объекта NULL с помощью [NSNull null]
, который совпадает с (id)kCFNull
Это можно сделать для всех подуровней, выполняя итерацию по всем подуровням слой просмотров с...
for (CALayer *iterationLayer in self.layer.sublayers ) {
iterationLayer.actions = [NSDictionary dictionaryWithObject:[NSNull null] forKey:@"position"];
//or for multiple keys at once
NSNull *nop = [NSNull null];
iterationLayer.actions = [NSDictionary dictionaryWithObjects:@[nop,nop] forKeys:@[@"position",@"contents"]];
}
Ответ 9
Это старый вопрос, но проблема остается. Иногда вам не нужны анимации, которые навязывает вам CALayer. Я не был доволен подходом, основанным на транзакциях, поскольку я просто хотел отключить эти действия. Для блага. Здесь представлено решение Swift 4 для подкласса CALayer, позволяющее выбрать, разрешить ли какое-либо действие или глобально отключить их. Вы также можете создавать подклассы CAShapeLayer, CATextLayer с тем же содержанием:
public class ActionCALayer: CALayer {
public var allowActions: Bool = false
override public func action(forKey event: String) -> CAAction? {
return allowActions ? super.action(forKey: event) : nil
}
}
Ответ 10
Я полностью согласен с Райаном. Его ответ - для MacOS, для iOS вы добавляете следующее, чтобы создать действие NSNull(). Этот вопрос Отключение неявной анимации в - [CALayer setNeedsDisplayInRect:] и документация в заголовке привели меня сюда
// Disable the implicit animation for changes to position
override open class func defaultAction(forKey event: String) -> CAAction? {
if event == #keyPath(position) {
return NSNull()
}
return super.defaultAction(forKey: event)
}