如何在 animateWithDuration 块期间利用 UIView 的变化值?

Posted

技术标签:

【中文标题】如何在 animateWithDuration 块期间利用 UIView 的变化值?【英文标题】:How can I tap into a UIView's changing values during an animateWithDuration block? 【发布时间】:2013-03-15 02:40:50 【问题描述】:

我正在使用 animateWithDuration 来更改 UISlider 的值:

[UIView animateWithDuration:1.0f
                      delay:0.0f
                    options:UIViewAnimationOptionCurveEaseInOut
                 animations:^ [myUISlider setValue:10]; 
                 completion:^(BOOL finished) ];

问题是,我需要能够显示 UISlider 的当前值而它正在改变。这甚至可以使用 animateWithDuration 吗?我尝试创建一个 UISlider 子类并覆盖 setValue 以希望在更改滑块时访问它的值:

-(void)setValue:(float)newValue

    [super setValue:newValue];

    NSLog(@"The new value is: %f",newValue);

但该代码仅在动画块的最结束处被调用。以一种完全合理的方式,因为我真的只调用了一次 setValue。但我希望动画块会以某种方式在其内部机制中一遍又一遍地调用它,但事实并非如此。

如果 UIView animateWithDuration 在这里是一个死胡同,我想知道是否有更好的方法来用其他东西实现同样的功能?也许我不知道 SDK 的另一个巧妙的小块驱动部分允许动画的不仅仅是 UIView 参数?

【问题讨论】:

【参考方案1】:

我认为最好的处理方法是编写一个自定义的Slide,你可以像进度条一样创建它,github上有很多演示。

你也可以使用NSTimer来做,但我不认为这是一个更好的方法。

当你点击时,你可以创建一个timer

_timer = [NSTimer scheduledTimerWithTimeInterval:.1 target:self selector:@selector(setValueAnimation) userInfo:nil repeats:YES];

并设置一个 ivar:_value = oldValue;

setValueAnimation 方法中:

- (void)setValueAnimation

    if (_value >= newValue) 
        [_timer invalidate];
        _value = newValue;
        [self setVale:_value];
        return;
    

    _value += .05;

    [self setVale:_value];


更新

如何添加块:

第一个:你可以定义一个块处理程序:

typedef void (^CompleteHandler)();

第二个:创建你的块并将其添加到 userInfo 中:

CompleteHandler block = ^()
    NSLog(@"Complete");
;

NSDictionary *userInfo = [[NSDictionary alloc] initWithObjectsAndKeys:block,@"block", nil];

第三个:制作NSTimer

_timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(setValueAnimation:) userInfo:userInfo repeats:YES];

第四个:实现你的计时器方法:

- (void)setValueAnimation:(NSTimer *)timer

    if (_value >= newValue) 
        [_timer invalidate];
        _value = newValue;
        [self setVale:_value];

        // also can use [_delegate complete];

        CompleteHandler block = [timer.userInfo objectForKey:@"block"];
        if (block) 

              block();

        
        return;
    

    _value += .05;

    [self setVale:_value];


【讨论】:

对,能在easeout参数和block结构中使用apple的ease就好了..也许不可能吧。 @todd412 当然你可以使用块和自定义“easein”“easeout”。您可以将块处理程序创建为 ivar ,并将其添加到 userInfo 中。您可以在“返回”之前调用块或回调委托来告诉您 setValueAnimation 已完成。您可以自己自定义时间函数来实现“easein”“easeout”它只是动态设置“_value += dynamicValue” @todd412 如果你按照我上面说的做,为什么不创建一个自定义的Silder 听起来很有趣,你能用一些示例代码编辑你的帖子,以显示你所描述的关于使用 userinfo 创建块的内容吗? @todd412 看到我的更新,也许你应该自己处理异常【参考方案2】:

我不知道是否有任何类型的通知可以“点击”以获取 UIView 动画“步骤”,但您可以使用 NSTimer“手动”执行动画,这将允许您连续更新你的价值。

【讨论】:

对,这可能是一个不错的选择,虽然它失去了内置 EaseIn 和 EaseOut 参数和块结构的便利性..【参考方案3】:

如果有使用 UIView 的开箱即用解决方案 - 我全神贯注。这个动画框架(只有 2 个类!) - PRTween https://github.com/chris838/PRTween 将让您访问方便的计时功能以及更改的值。

这是我的一个更新项目https://github.com/jdp-global/KACircleProgressView/

PRTweenPeriod *period = [PRTweenPeriod periodWithStartValue:0 endValue:10.0 duration:1.0];

PRTweenOperation *operation = [PRTweenOperation new];
operation.period = period;
operation.target = self;
operation.timingFunction = &PRTweenTimingFunctionLinear;
operation.updateSelector = @selector(update:)

[[PRTween sharedInstance] addTweenOperation:operation]

- (void)update:(PRTweenPeriod*)period 
  [myUISlider setValue:period.tweenedValue];

【讨论】:

以上是关于如何在 animateWithDuration 块期间利用 UIView 的变化值?的主要内容,如果未能解决你的问题,请参考以下文章

在 animateWithDuration:completion 的完成块中删除 UIView

我的 animatewithduration,完成块只执行一次

UIView animateWithDuration 动画块之外的动画自动布局视图

强制调用 UIView animateWithDuration 完成块

在 UIView 的 animateWithDuration 块方法中阻止 self 和 dot 访问器的作用域

ios - UIView.animateWithDuration 的交互式过渡完成块从未在 animateTransition 内部调用