gpt4 book ai didi

ios - UIViewAnimationOptionBeginFromCurrentState 基本动画的意外行为

转载 作者:可可西里 更新时间:2023-11-01 03:54:26 25 4
gpt4 key购买 nike

我正在尝试在收到按钮点击时执行这个基本的 UIView 动画:

- (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];
}

在单击按钮之前, View 是可见的并且具有 1.0 的 alpha 值。当我发送按钮操作时,我希望 View 在 2 秒内从 alpha=0.0 淡入到 alpha=1.0,但这并没有发生。当我删除 UIViewAnimationOptionBeginFromCurrentState 时,动画效果很好。

似乎设置了 UIViewAnimationOptionBeginFromCurrentState 选项,未设置 alpha=0.0 并且动画被跳过,因为它认为它已经是 1.0。

我试图理解为什么会发生这种情况,因为 Apple 文档指出如果另一个动画未在进行中,UIViewAnimationOptionBeginFromCurrentState 无效:

"UIViewAnimationOptionBeginFromCurrentState从与已经在飞行中的动画关联的当前设置开始动画。如果此键不存在,则允许在新动画开始之前完成任何飞行中的动画。如果另一个动画不在飞行中,则此键无效。”

最佳答案

事实证明,使用 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];
}];
}

提及 animateWithDuration:0!!!

规则很简单:仅在其他动画 block 之后使用带有 UIViewAnimationOptionBeginFromCurrentState 的动画 block ,以便实际应用您之前的所有更改。

如果您不知道 animateWithDuration:0 block 中到底应该包含什么,那么您可以使用这个技巧:

- (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];
}];
}

如果你不想记住这个错误的所有细节,那么只需申请 Method Swizzling到 UIView 类。

重要编辑:事实证明,如果调用 performBatchUpdates:completion:,下面的代码将导致运行时崩溃>UICollectionView 实例。所以,我不建议在这种情况下使用method 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];
}

就我而言,这个错误完全毁了我的动画。见下文:

[ Demo CountPages alpha ][ Demo CountPages alpha ]

关于ios - UIViewAnimationOptionBeginFromCurrentState 基本动画的意外行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21495970/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com