MDJ*_*MDJ 16 objective-c uiview ios
我是Objective-C/iOS编程的新手,我正在努力了解UIView动画是如何工作的.
说我有这样的代码:
[UIView animateWithDuration:2.0 animations:^{
self.label.alpha = 1.0;
}];
Run Code Online (Sandbox Code Playgroud)
作为animations参数传递的东西是可以执行的Objective-C块(类似于其他语言中的lambdas/anonymous函数),然后它将当前值的alpha属性更改label为1.0.
但是,该块不接受动画进度参数(例如从0.0到1.0或从0到1000).我的问题是动画框架如何使用此块来了解中间帧,因为块仅指定最终状态.
编辑:我的问题是有关,而引擎盖下的操作animateWithDuration方法,而不是使用它的方式.
我对animateWithDuration代码如何工作的假设如下:
animateWithDuration 为所有视图对象激活某种特殊状态,其中实际上没有执行更改但仅注册了.有人能否说明animateWithDuration这种方式是否真的有效?
omz*_*omz 20
当然我不知道幕后究竟发生了什么,因为UIKit不是开源的,我不在Apple工作,但这里有一些想法:
在UIView引入基于块的动画方法之前,动画视图看起来像这样,并且这些方法实际上仍然可用:
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:duration];
myView.center = CGPointMake(300, 300);
[UIView commitAnimations];
Run Code Online (Sandbox Code Playgroud)
知道这一点,我们可以实现我们自己的基于块的动画方法,如下所示:
+ (void)my_animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations
{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:duration];
animations();
[UIView commitAnimations];
}
Run Code Online (Sandbox Code Playgroud)
...这与现有animateWithDuration:animations:方法完全相同.
从块中取出块,很明显必须有某种全局动画状态,UIView然后在动画块中完成动画时,可以使用这些动画状态对其(动画)属性进行动画处理.这必须是某种堆栈,因为您可以拥有嵌套的动画块.
实际动画由Core Animation执行,Core Animation在图层级别工作 - 每个动画UIView都有一个CALayer负责动画和合成的支持实例,而视图主要处理触摸事件和协调系统转换.
我不会在这里详细介绍Core Animation的工作原理,您可能需要阅读核心动画编程指南.从本质上讲,它是一个动画层树动画的系统,无需显式计算每个关键帧(实际上很难从Core Animation中获取中间值,通常只需指定值和持续时间等,然后让系统使用照顾细节).
因为它UIView是基于a的CALayer,所以它的许多属性实际上是在底层实现的.例如,当你设置或获取时view.center,它是相同的,view.layer.location并且更改其中任何一个也将改变另一个.
可以使用显式动画层CAAnimation(这是一个具有许多具体实现的抽象类,例如CABasicAnimation简单的事物和CAKeyframeAnimation更复杂的东西).
那么UIView属性设置器可以做什么来完成动画块中的"神奇"动画更改?让我们看看我们是否可以重新实现其中一个,为了简单起见,让我们使用setCenter:.
首先,这里是my_animateWithDuration:animations:上面使用全局的方法的修改版本CATransaction,这样我们就可以在我们的setCenter:方法中找出动画需要多长时间:
- (void)my_animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations
{
[CATransaction begin];
[CATransaction setAnimationDuration:duration];
animations();
[CATransaction commit];
}
Run Code Online (Sandbox Code Playgroud)
请注意,我们不再使用beginAnimations:...它commitAnimations,所以不做任何其他事情,什么都不会动画.
现在,让我们setCenter:在UIView子类中重写:
@interface MyView : UIView
@end
@implementation MyView
- (void)setCenter:(CGPoint)position
{
if ([CATransaction animationDuration] > 0) {
CALayer *layer = self.layer;
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position"];
animation.fromValue = [layer valueForKey:@"position"];
animation.toValue = [NSValue valueWithCGPoint:position];
layer.position = position;
[layer addAnimation:animation forKey:@"position"];
}
}
@end
Run Code Online (Sandbox Code Playgroud)
在这里,我们使用Core Animation 设置一个显式动画,动画创建底层的location属性.动画的持续时间将自动从中获取CATransaction.我们来试试吧:
MyView *myView = [[MyView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
myView.backgroundColor = [UIColor redColor];
[self.view addSubview:myView];
[self my_animateWithDuration:4.0 animations:^{
NSLog(@"center before: %@", NSStringFromCGPoint(myView.center));
myView.center = CGPointMake(300, 300);
NSLog(@"center after : %@", NSStringFromCGPoint(myView.center));
}];
Run Code Online (Sandbox Code Playgroud)
我并不是说这正是UIView动画系统的工作方式,而是说明它原则上是如何工作的.
| 归档时间: |
|
| 查看次数: |
3380 次 |
| 最近记录: |