有没有办法让 CALayer 的动作字典永久优先于其 UIView 委托?
我遇到以下情况:
在视图控制器内,我开始创建任意数量的透明 UIButton,这些按钮在控制器的主视图上切换 UIView 的出现和消失。现在,当我的“放大”和“缩小”方法被调用时,有一些代码用于修改两个 CALayer 属性的默认动画(实际上只是持续时间)。每次发生操作时都会调用此代码。但我想在图层内部设置一次动画代码,而不是将其放在缩放方法中。在展示基本想法后,我将解释更多内容:
按钮/传感器创建代码太长,无法发布(与真正的问题无关),但它与此伪代码类似:
- (void) createSensors:[number of sensors]
{
for(number of sensors)
{
create UIVIew with some content;
create transparent UIBUtton as sensor and place somewhere in main view;
calculate a transform to "shrink" the UIView's layer to the size and position of the button.
apply transform;
set the UIVIew's layer opacity to 0;
add UIVIew to main view
(but the rest of my interface is in a container view, so I can dim the screen and have this view displayed in a modal-like way.)
do some tagging so the button's tag can later be used to retrieve this view and transform.
}
}
现在,当传感器单击后,我对与传感器/视图关联的视图执行“放大”。实际上,我将屏幕调暗为白色,并对视图(图层的实际)位置进行动画处理并缩放到屏幕中心。单击视图中的按钮时,我会执行相反的操作来关闭它。这是代码:
- (void)animateZoomIn:(UIButton*)sender
{
NSString *sourceTagKey = [NSString stringWithFormat:@"%i",sender.tag];
AnimationSettings *settings = [zoomTransforms objectForKey:sourceTagKey];
UIView *newBox = [[self.view subviews] objectAtIndex:sender.tag];
activeZoomBox = newBox;
CABasicAnimation *a = [CABasicAnimation animation];
a.duration = .4;
[mainCanvas.layer addAnimation:a forKey:@"opacity"];
a = [CABasicAnimation animation];
a.duration = 1;
[activeZoomBox.layer addAnimation:a forKey:@"opacity"];
a = [CABasicAnimation animation];
a.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
a.duration = .5;
[activeZoomBox.layer addAnimation:a forKey:@"transform"];
[mainCanvas setUserInteractionEnabled:NO];
if([settings wantsBackgroundFade])
[mainCanvas.layer setOpacity:.2];
[activeZoomBox.layer setOpacity:1];
[activeZoomBox.layer setTransform:CATransform3DIdentity];
}
- (void)animateZoomOut:(UIButton*)sender
{
NSString *sourceTagKey = [NSString stringWithFormat:@"%i",sender.tag];
AnimationSettings *settings = [zoomTransforms objectForKey:sourceTagKey];
CABasicAnimation *a = [CABasicAnimation animation];
a.duration = .4;
[mainCanvas.layer addAnimation:a forKey:@"opacity"];
a = [CABasicAnimation animation];
a.duration = 1;
[activeZoomBox.layer addAnimation:a forKey:@"opacity"];
a = [CABasicAnimation animation];
a.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
a.duration = .5;
[activeZoomBox.layer addAnimation:a forKey:@"transform"];
[mainCanvas setUserInteractionEnabled:YES];
if([settings wantsBackgroundFade])
[mainCanvas.layer setOpacity:1];
[activeZoomBox.layer setOpacity:0];
[activeZoomBox.layer setTransform:[settings transform]];
}
所以问题:
我不想
CABasicAnimation *a = [CABasicAnimation animation];
a.duration = .4;
[mainCanvas.layer addAnimation:a forKey:@"opacity"];
在操作方法中使用这种代码。我宁愿替换动画一次,并使其对于创建的每个图层和 mainCanvas 视图“永久”。例如,我更愿意在控制器的 init 方法上使用此代码一次,然后忘记它:
CABasicAnimation *a = [CABasicAnimation animation];
a.duration = .4;
NSMutableDictionary *animations = [NSMutableDictionary dictionaryWithDictionary:[mainCanvas.layer actions]];
[animations setObject:a forKey:@"opacity"];
[mainCanvas.layer setActions:animations];
然后,每当我调用 [mainCanvas setOpacity:] 时,默认情况下它都会持续 0.4 秒。使用无委托的 CALayer 就可以了。但是在这种情况下,我的层将其视图作为委托,这些视图优先于操作字典,并且我有点需要将视图作为委托。
那么有没有办法仍然图层是否对字典做出响应?如果没有,“永久替换”或向这些图层添加动画的最佳方法是什么,以便动画包含在图层对象中(这就是为什么我不想重写 CAAction 的视图委托方法)协议)?
I have the following situation:
From within a view controller, I go about creating an arbitrary number of transparent UIButtons which toogle the appearance and disappearance of UIViews over the controller's main view. Right now, when my "zoom in" and "zoom out" methods are called, there's code for modifying the default animation of two CALayer properties (just duration really). This code then gets called every time the actions take place. But I'd like to set the animation code once inside the layer and not have it in the zoom methods. I'll explain more after I show the basic idea:
The buttons/sensors creation code is too long to post (and not that relevant to the real question), but it's something along the lines of this pseudo code:
- (void) createSensors:[number of sensors]
{
for(number of sensors)
{
create UIVIew with some content;
create transparent UIBUtton as sensor and place somewhere in main view;
calculate a transform to "shrink" the UIView's layer to the size and position of the button.
apply transform;
set the UIVIew's layer opacity to 0;
add UIVIew to main view
(but the rest of my interface is in a container view, so I can dim the screen and have this view displayed in a modal-like way.)
do some tagging so the button's tag can later be used to retrieve this view and transform.
}
}
Now, when a sensor is clicked, I perform a "zoom in" for the view associated with the sensor/view. I actually dim the screen to white, and animate the view's (the layer's really) position and scaling to the center of the screen. And on clicking a button in the view, I do the opposite to dismiss it. This is the code:
- (void)animateZoomIn:(UIButton*)sender
{
NSString *sourceTagKey = [NSString stringWithFormat:@"%i",sender.tag];
AnimationSettings *settings = [zoomTransforms objectForKey:sourceTagKey];
UIView *newBox = [[self.view subviews] objectAtIndex:sender.tag];
activeZoomBox = newBox;
CABasicAnimation *a = [CABasicAnimation animation];
a.duration = .4;
[mainCanvas.layer addAnimation:a forKey:@"opacity"];
a = [CABasicAnimation animation];
a.duration = 1;
[activeZoomBox.layer addAnimation:a forKey:@"opacity"];
a = [CABasicAnimation animation];
a.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
a.duration = .5;
[activeZoomBox.layer addAnimation:a forKey:@"transform"];
[mainCanvas setUserInteractionEnabled:NO];
if([settings wantsBackgroundFade])
[mainCanvas.layer setOpacity:.2];
[activeZoomBox.layer setOpacity:1];
[activeZoomBox.layer setTransform:CATransform3DIdentity];
}
- (void)animateZoomOut:(UIButton*)sender
{
NSString *sourceTagKey = [NSString stringWithFormat:@"%i",sender.tag];
AnimationSettings *settings = [zoomTransforms objectForKey:sourceTagKey];
CABasicAnimation *a = [CABasicAnimation animation];
a.duration = .4;
[mainCanvas.layer addAnimation:a forKey:@"opacity"];
a = [CABasicAnimation animation];
a.duration = 1;
[activeZoomBox.layer addAnimation:a forKey:@"opacity"];
a = [CABasicAnimation animation];
a.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
a.duration = .5;
[activeZoomBox.layer addAnimation:a forKey:@"transform"];
[mainCanvas setUserInteractionEnabled:YES];
if([settings wantsBackgroundFade])
[mainCanvas.layer setOpacity:1];
[activeZoomBox.layer setOpacity:0];
[activeZoomBox.layer setTransform:[settings transform]];
}
So, the question:
I'd like to not have this kind of code:
CABasicAnimation *a = [CABasicAnimation animation];
a.duration = .4;
[mainCanvas.layer addAnimation:a forKey:@"opacity"];
in the action methods. I'd rather replace the animation once and make it "permanent" for each layer created and for the mainCanvas view. For instance, I'd prefer to have this code once on the controller's init method and forget about it:
CABasicAnimation *a = [CABasicAnimation animation];
a.duration = .4;
NSMutableDictionary *animations = [NSMutableDictionary dictionaryWithDictionary:[mainCanvas.layer actions]];
[animations setObject:a forKey:@"opacity"];
[mainCanvas.layer setActions:animations];
Then, whenever I'd call [mainCanvas setOpacity:] it would last .4 secs by default. With a delegate-less CALayer it'd work.But in this case, my layers have their views as delegates, which have precedence over the actions dictionary, and I sort of need the views as delegates..
So is there a way to still have the layers respond to the dictionary instead? And if not, what would be the best way to "permanently replace" or add animations to these layers, so that the animations are contained in the layer objects (which is why I'd prefer to not override the view's delegate methods for the CAAction Protocol)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
为什么不直接覆盖 UIView 上的
-actionForLayer:forKey:
来提供您想要的重要按键操作(并为其他按键调用 super )?无法更改优先级,因此您唯一的选择是实施-actionForLayer:forKey:
或使用手动动画。Why not just override
-actionForLayer:forKey:
on the UIView to provide the action you want on the important keys (and call super for the others)? There is no way to change the precedence, so your only options are implement-actionForLayer:forKey:
or go with the manual animations.