Ios UIViewAnimationOptionBeginFromCurrentState基本动画的意外行为
我正在尝试在收到按钮单击后执行此基本Ios UIViewAnimationOptionBeginFromCurrentState基本动画的意外行为,ios,objective-c,cocoa-touch,uiviewanimation,Ios,Objective C,Cocoa Touch,Uiviewanimation,我正在尝试在收到按钮单击后执行此基本ui视图动画: - (IBAction)buttonPress:(id)sender { self.sampleView.alpha = 0.0; [UIView animateWithDuration:2.0 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimat
ui视图
动画:
- (IBAction)buttonPress:(id)sender
{
self.sampleView.alpha = 0.0;
[UIView animateWithDuration:2.0
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionBeginFromCurrentState
animations:^{self.sampleView.alpha = 1.0;}
completion:NULL];
}
单击按钮之前,视图可见,且alpha值为1.0。当我发送按钮动作时,我希望视图在2秒内从alpha=0.0淡入alpha=1.0,但这不会发生。当我删除UIViewAnimationOptionBeginFromCurrentState
时,动画工作正常
似乎设置了UIViewAnimationOptionBeginFromCurrentState
选项后,alpha=0.0没有被设置,动画被跳过,因为它认为它已经处于1.0
我正在试图理解为什么会发生这种情况,因为苹果的文档说明,如果没有其他动画进行,则UIViewAnimationOptionBeginFromCurrentState
无效:
“UIViewAnimationOptionBeginFromCurrentState
从与已在运行中的动画相关联的当前设置启动动画。如果此键不存在,则允许在启动新动画之前完成任何在运行中的动画。如果另一个动画不在运行中,则此键无效。“为了查看发生了什么,为帧位置而不是alpha设置动画很有帮助。如果执行此操作,请尝试每隔一秒左右用
UIViewAnimationOptionBeginFromCurrentState
设置点击按钮,您将开始看到一些移动
将alpha设置为零时,直到下一次通过运行循环时,才会更新显示。由于随后立即启动动画,因此显示没有机会更新,当动画框架启动时,它会查看当前显示的alpha(1.0)并查看其必须到达的位置(alpha为1.0),而两者之间的插值不会产生任何效果
如果需要将UIViewAnimationOptionBeginFromCurrentState
选项保留在其中,因为当此视图上的动画已在进行时,可能会点击此按钮,则可以执行以下操作:
- (IBAction)buttonPressed:(id)sender
{
self.sampleView.alpha = 0.0;
[self performSelector:@selector(animateAlpha) withObject:nil afterDelay:0.1];
}
- (void)animateAlpha
{
[UIView animateWithDuration:2.0
delay:0.0
options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionBeginFromCurrentState
animations:^{self.sampleView.alpha = 1.0;}
completion:NULL];
}
当使用
UIViewAnimationOptionBeginFromCurrentState
而不是PerformSelect:
时,我喜欢在调用animateWithDuration:
之前,使用UIViewAnimationOptionBeginFromCurrentState
设置初始值
看看这个例子:
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
UIButton *theButton = [UIButton new];
[self.view addSubview:theButton];
theButton.frame = self.view.frame;
theButton.backgroundColor = [UIColor redColor];
theButton.alpha = 0.05;
[theButton addTarget:self action:@selector(actionPressed:) forControlEvents:UIControlEventTouchUpInside];
}
- (void)actionPressed:(UIButton *)theButton
{
theButton.alpha = 0.6;
[UIView animateWithDuration:5
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^
{
// you expect to animate from 0.6 to 1. but it animates from 0.05 to 1
theButton.alpha = 1;
}
completion:nil];
}
在上面的示例中,您希望.alpha
将从0.6设置为1。但是,它的动画范围为0.05到1
要解决此问题,应将actionPressed:
更改为以下内容:
- (void)actionPressed:(UIButton *)theButton
{
[UIView animateWithDuration:0
animations:^
{
// set new values INSIDE of this block, so that changes are
// captured in UIViewAnimationOptionBeginFromCurrentState.
theButton.alpha = 0.6;
}
completion:^(BOOL finished)
{
[UIView animateWithDuration:5
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^
{
// now it really animates from 0.6 to 1
theButton.alpha = 1;
}
completion:nil];
}];
}
提及持续时间为0的动画
规则很简单:仅在其他动画块之后使用带有UIViewAnimationOptionBeginFromCurrentState
的动画块,以便实际应用之前的所有更改。
如果您不知道在animateWithDuration:0
块中应该包含什么,那么您可以使用以下技巧:
- (void)actionPressed:(UIButton *)theButton
{
// make all your changes outside of the animation block
theButton.alpha = 0.6;
// create a fake view and add some animation to it.
UIView *theFakeView = [UIView new];
theFakeView.alpha = 1;
[UIView animateWithDuration:0
animations:^
{
// we need this line so that all previous changes are ACTUALLY applied
theFakeView.alpha = 0;
}
completion:^(BOOL finished)
{
[UIView animateWithDuration:5
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^
{
// now it really animates from 0.6 to 1
theButton.alpha = 1;
}
completion:nil];
}];
}
如果您不想记住这个bug的所有细节,那么只需应用到UIView类
重要编辑:如果调用UICollectionView
实例的performbatchUpdate:completion:
,下面的代码将在运行时导致崩溃。因此,我不建议在这种情况下使用方法swizzling
您的代码可能如下所示:
+ (void)load
{
static dispatch_once_t theOnceToken;
dispatch_once(&theOnceToken, ^
{
Class theClass = object_getClass(self);
SEL theOriginalSelector = @selector(animateWithDuration:delay:options:animations:completion:);
SEL theSwizzledSelector = @selector(swizzled_animateWithDuration:delay:options:animations:completion:);
Method theOriginalMethod = class_getClassMethod(theClass, theOriginalSelector);
Method theSwizzledMethod = class_getClassMethod(theClass, theSwizzledSelector);
if (!theClass ||!theOriginalSelector || !theSwizzledSelector || !theOriginalMethod || !theSwizzledMethod)
{
abort();
}
BOOL didAddMethod = class_addMethod(theClass,
theOriginalSelector,
method_getImplementation(theSwizzledMethod),
method_getTypeEncoding(theSwizzledMethod));
if (didAddMethod)
{
class_replaceMethod(theClass,
theSwizzledSelector,
method_getImplementation(theOriginalMethod),
method_getTypeEncoding(theOriginalMethod));
}
else
{
method_exchangeImplementations(theOriginalMethod, theSwizzledMethod);
}
});
}
+ (void)swizzled_animateWithDuration:(NSTimeInterval)duration
delay:(NSTimeInterval)delay
options:(UIViewAnimationOptions)options
animations:(void (^)(void))animations
completion:(void (^)(BOOL))completion
{
if (options & UIViewAnimationOptionBeginFromCurrentState)
{
UIView *theView = [UIView new];
theView.alpha = 1;
[UIView animateWithDuration:0
animations:^
{
theView.alpha = 0;
}
completion:^(BOOL finished)
{
[self swizzled_animateWithDuration:duration
delay:delay
options:options
animations:animations
completion:completion];
}];
}
else
{
[self swizzled_animateWithDuration:duration
delay:delay
options:options
animations:animations
completion:completion];
}
}
如果将此代码添加到自定义UIView类别,则此代码现在可以正常工作:
- (void)actionPressed:(UIButton *)theButton
{
theButton.alpha = 0.6;
[UIView animateWithDuration:5
delay:0
options:UIViewAnimationOptionBeginFromCurrentState
animations:^
{
// you expect to animate from 0.6 to 1.
// it will do so ONLY if you add the above code sample to your project.
theButton.alpha = 1;
}
completion:nil];
}
在我的例子中,这个bug完全破坏了我的动画。见下文:
[]
[]这太令人困惑了。我只能猜测它与UIView的alpha值的实际状态有关。它从1.0开始,这是完整值。即使苹果公司声明它忽略了它,你在它下面还有其他动画吗?是的,我最好的猜测是,在动画开始时,当前的alpha值仍然是1.0,因为0.0还没有机会在屏幕上更新。因为动画值是1.0,而当前屏幕上的值也是1.0,所以它可能认为没有变化,也没有动画出现。我同意这一点。我想既然你的动画看起来很小,你就不需要使用当前状态部分了。看看去掉它是否会改变任何东西去掉UIViewAnimationOptionBeginFromCurrentState肯定能解决我所看到的问题(参见原始帖子)。但是,在我的应用程序中,我打算使用此选项,因为我希望我的动画偶尔会被另一个动画打断,并且我希望从一个动画平滑过渡到另一个动画。我想知道为什么包含它会产生不同的行为。