有没有办法让 CALayer 的动作字典永久优先于其 UIView 委托?

Posted

技术标签:

【中文标题】有没有办法让 CALayer 的动作字典永久优先于其 UIView 委托?【英文标题】:Is there a way to give a CALayer's action dictionary permanent precendece over its UIView delegate? 【发布时间】:2012-01-28 21:59:06 【问题描述】:

我有以下情况:

从视图控制器中,我开始创建任意数量的透明 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 委托方法的原因协议)?

【问题讨论】:

【参考方案1】:

为什么不直接覆盖 UIView 上的 -actionForLayer:forKey: 以在重要键上提供您想要的操作(并为其他键调用 super)?无法更改优先级,因此您唯一的选择是实现 -actionForLayer:forKey: 或使用手动动画。

【讨论】:

以上是关于有没有办法让 CALayer 的动作字典永久优先于其 UIView 委托?的主要内容,如果未能解决你的问题,请参考以下文章

图像约束优先于标签

如何让 CSS 类优先于 id?

springboot怎么让自定义的拦截器优先于pagehelper执行

为啥&&和||优先于 -a 和 -o

Java1.8 ​lamda+方法引用 + 函数式接口

TouchableOpacity 内的 ScrollView