问题
Is there any way to tell if a UIView is in the middle of an animation? When I print out the view object while it is moving I notice that there is an "animations" entry:
search bar should end editing: <UISearchBar: 0x2e6240; frame = (0 0; 320 88); text = ''; autoresize = W+BM; animations = { position=<CABasicAnimation: 0x6a69c40>; bounds=<CABasicAnimation: 0x6a6d4d0>; }; layer = <CALayer: 0x2e6e00>>
When the animation has stopped and I print the view, the "animations" entry is now gone:
search bar should end editing: <UISearchBar: 0x2e6240; frame = (0 0; 320 88); text = ''; autoresize = W+BM; layer = <CALayer: 0x2e6e00>>
回答1:
A UIView
has a layer (CALayer). You can send animationKeys to it, which will give you an array of keys which identify the animations attached to the layer. I suppose that if there are any entries, the animation(s) are running. If you want to dig even deeper have a look at the CAMediaTiming protocol which CALayer
adopts. It does some more information on the current animation.
Important: If you add an animation with a nil
key ([layer addAnimation:animation forKey:nil]
), animationKeys
returns nil
.
回答2:
Animations are attached in fact to the underlying Core Animation CALayer
class
So I think you can just check myView.layer.animationKeys
回答3:
iOS 9+ method, works even when layer.animationKeys
contains no keys:
let isInTheMiddleOfAnimation = UIView.inheritedAnimationDuration > 0
From the docs:
This method only returns a non-zero value if called within a UIView animation block.
回答4:
I'm not sure of the context of the question but I had was attempting to find out if a view was animating before starting a second animation to avoid skipping. However there is a UIView animation option UIViewAnimationOptionBeginFromCurrentState
that will combine the animations if necessary to give a smooth appearance. Thereby eliminating my need to know if the view was animating.
回答5:
There is a hitch with the animationKeys trick.
Sometimes there could be a few animationKeys lingering after an animation is completed.
This means that a non-animating layer could return a set of animationKeys even if it isn't actually animating.
You can make sure that animationKeys are automatically removed by setting an animation's removedOnCompletion property to YES.
e.g.
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"aPath"];
animation.removedOnCompletion = YES;
If you do this for all the animations you apply to your layer, it will ensure that when the layer isn't animating there are no animationKeys present.
回答6:
Some of these didn't work for me. The reason for that is that these animations are asynchronous.
What I did is defined a property
@property BOOL viewIsAnimating;
And in my animation
[UIView animateWithDuration:0.25
animations:^{
viewIsAnimating = YES;
} completion:^(BOOL finished) {
if (finished) {
viewIsAnimating = NO;
}
}];
回答7:
Ref to the question: UIView center position during animation
I compare the view's frame and layer.presentation()?.frame to check it is animating. If leftView is on the way to finish, the leftView.layer.presentation()?.frame does not equal to its frame:
if self.leftView.layer.presentation()?.frame == self.leftView.frame {
// the animation finished
} else {
// the animation on the way
}
But this method may not work if the view move to the end position during the animation. More condition check may be necessary.
回答8:
There are a lot of out-of-date answers here. I just needed to prevent a UIView
animation being started if there was one running on the same view, so I created a category on UIView
:-
extension UIView {
var isAnimating: Bool {
return (self.layer.animationKeys()?.count ?? 0) > 0
}
}
This way I can just check any view's animation status like this:-
if !myView.isAnimating {
UIView.animate(withDuration: 0.4) {
...
}
} else {
// already animating
}
This seems less fragile than keeping track of it with a state variable.
回答9:
You could query the presentation layer as suggested here My presentation layer does not match my model layer even though I have no animations
回答10:
You can use the layer property of a UIView. CALayer has a property called animation keys, you can check its count if it is greater than 0.
if (view.layer.animationKeys.count) {
// Animating
}else {
// No
}
In the Documentation:
-(nullable NSArray<NSString *> *)animationKeys;
Returns an array containing the keys of all animations currently * attached to the receiver. The order of the array matches the order * in which animations will be applied.
来源:https://stackoverflow.com/questions/5526476/test-whether-a-uiview-is-in-the-middle-of-animation