Chr*_*orr 11 calayer uiview uiviewanimation ios
我有一个容器视图 - 让我们称之为套接字视图 - 它有一个子视图,它是内容视图 - 让我们称之为插件视图.此插件视图可以为nil,即套接字视图当前为空.如果它确实包含一个插件视图,它将占用整个套接字的空间,即它的框架是套接字的边界.从外观来看,你甚至不能告诉它实际上有两个视图,因为插件视图总是与套接字完全相同.
我正在努力让动画正常工作:如果插件视图存在并在动画之前布局,一切都按预期工作.但是,如果我只在动画已经运行时才设置套接字的插件视图,我会得到一个不希望的效果:
插件视图布局到动画结束时的位置,并且不会在其插槽旁边进行动画处理.我希望它看起来像是一直存在但只是刚才可见,即插件视图(及其子视图)应该在套接字旁边动画,即使我在动画进行过程中添加它.
我怎样才能实现这种行为?
我的想法:显然插件视图必须布置两次:一次用于最终位置,再一次用于套接字视图开始动画或添加的位置.我可以计算这个帧,在没有动画的情况下应用它,并在新的动画块中动画到最终帧.为了使动画定时保持一致,我需要具有相同的曲线和持续时间,但过去开始动画或以某种方式转发动画.这可能吗?是否有其他方法具有插头观点是完全的宽度和高度在任何时候?
作为Rob的回答的后续内容,以下是我正在寻找的更多细节:
套接字视图是动画的,因为它的所有者的绑定大小已更改.您可以将其视为表视图中的全宽度单元格.
插件视图可以包含其自身的子视图,如图像视图,标签等.这些也应该加入到套接字视图的动画中,就好像它们自动画开始以来一直存在.
虽然理论上有一个新动画可以在一个已经运行时启动,但我并不介意这个边缘情况下的行为.
在动画运行时,用户无需与插件视图交互; 无论如何,这很可能发生在界面方向改变期间.
插件视图可能会决定在动画时由于异步模型更新而更改其内容,但这又是一个边缘情况,我不介意动画在这种情况下看起来不完美.但是,它的大小不会改变 - 它总是与插件视图的大小相同.
您说您的插件视图应该完全覆盖套接字视图.我们需要担心两件事:插件的图层位置(layer.position)和图层尺寸(layer.bounds.size).
默认情况下,position控制图层(和视图)的中心,因为默认anchorPoint值为(0.5,0.5).如果我们设置anchorPoint为(0,0),则position控制图层的左上角,我们总是希望它在套接字坐标系中为(0,0).因此,通过设置both anchorPoint和positionto CGPointZero,我们可以避免担心动画layer.position.
那只是让我们动画layer.bounds.size.
使用UIKit动画为视图设置动画时,它会创建CABasicAnimation引擎盖下的实例.CABasicAnimation是CAAnimation添加(以及其他内容)fromValue和toValue属性的子类,指定动画的开始和结束值.
CAAnimation符合CAMediaTiming协议,这意味着它具有beginTime属性.创建时CAAnimation,它的默认值beginTime为零.核心动画CACurrentMediaTime在提交当前事务时将其更改为当前时间(请参阅参考资料).
但是如果动画已经非零beginTime,则Core Animation会按原样使用它.如果这beginTime是过去的,那么当动画首次出现在屏幕上时,动画已经部分(或甚至完全)完成,并且已经绘制了适当的进度.我们基本上可以"回溯"一个动画.
因此,如果我们挖掘CABasicAnimation控制插座bounds.size并将其添加到插头中,插头应该按照我们想要的方式进行动画制作.当我们将动画附加到插件时,它beginTime就是它开始设置套接字动画的时间.因此,即使我们稍后将它附加到插头上,它也会与插座完美同步.既然我们想要的插头和插座具有相同的大小,fromValue并且toValue也已经是正确的.
在我的测试应用程序中,我将插座设为粉红色,插头为蓝色.每个都是UIImageView显示边缘有线条的图像,因此我们可以确保视图始终具有正确的大小.这是它在行动中的样子:
还有一个转折点.如果为已经设置动画的视图设置动画,UIKit不会暂停之前的动画.它添加了第二个动画,两个动画同时运行.
这是有效的,因为UIKit使用了附加动画.当您将视图的宽度设置为320到160时,UIKit会立即将宽度设置为160,并添加一个从160到0的加法动画.在动画开始时,视在宽度为160 + 160 = 320,并且最后,表观宽度为160 + 0 = 160.
当UIKit在第一个动画运行时添加第二个动画时,两个动画的值都会添加到用于在屏幕上绘制视图的视在值.这是效果:
这意味着对我们来说,我们必须寻找所有与插座动画keyPath的position.size,和他们都复制到插头.这是我的测试应用程序中的代码:
- (IBAction)plugWasTapped:(id)sender {
if (self.plugView.superview) {
[self.plugView removeFromSuperview];
return;
}
self.plugView.frame = self.socketView.bounds;
[self.socketView addSubview:self.plugView];
for (NSString *key in self.socketView.layer.animationKeys) {
CAAnimation *rawAnimation = [self.socketView.layer animationForKey:key];
if (![rawAnimation isKindOfClass:[CABasicAnimation class]]) {
continue;
}
CABasicAnimation *animation = (CABasicAnimation *)rawAnimation;
if ([animation.keyPath isEqualToString:@"bounds.size"]) {
[self.plugView.layer addAnimation:animation forKey:key];
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是多个同步动画的结果:
让插件视图的完整视图层次结构生成动画就好像它本来就在那里一样,坦率地说太多了.
这是另一种选择:
这是它的样子:
除了交叉渐变的不完美之外,该版本不能处理同时运行的多个动画.您可以在我的存储库中的crossfade标记下找到它(在顶部链接).
另一种方法是仅将插件视图渲染为其最终大小,并将其放在占位符中而不进行交叉淡化.它看起来像这样:
我认为这种方式看起来更好,这个版本处理堆叠的动画.您可以在我的存储库中的stretch-end-image标记下找到它.
最后,我没有实现完全不同的方法.这仅适用于调整您自己创建的动画的大小 - 它不适用于系统在方向更改时创建的旋转动画.您可以使用计时器自行设置套接字视图边界的动画,而不是使用UIKit动画.WWDC 2012会议228:掌握自动布局的最佳实践最后讨论了这一点.他建议使用一个,NSTimer但我认为你最好使用一个CADisplayLink.如果采用这种方法,插件视图的子视图将完全动画.这比使用UIKit动画要多得多,但应该直截了当地实现.
| 归档时间: |
|
| 查看次数: |
1122 次 |
| 最近记录: |