如何为 UIView 的框架及其子层之一的框架设置动画?

how to animate both the frame of an UIView and the frame of one of its sublayers?

我有:

我有一个 UIView(名为 pView),它有一个 CAGradientLayer 作为子层。实际上是这样的: ViewController -> 视图 ->pView -> CAGradientLayer

这是创建这一切的代码:

@implementation ViewController  

- (void)viewDidLoad {
  [super viewDidLoad];

  UITestView * pView = nil;
  UIColor * scolor = nil, *ecolor = nil;
  self.view.backgroundColor = [UIColor yellowColor];

  pView = [[UITestView alloc] initWithFrame: CGRectMake(self.view.frame.origin.x, 100.0, self.view.frame.size.width, 100.0)];
  scolor = [UIColor colorWithRed:(14/255.0) green: (238/255.0) blue:(123/255.0) alpha:1];
  ecolor = [UIColor colorWithRed:(6/255.0) green: (216/255.0) blue:(69/255.0) alpha:1];

  // creating the gradient layer    
  CAGradientLayer * layer = [[CAGradientLayer alloc] init];
  layer.frame = self.bounds;
  layer.colors = @[(id)scolor.CGColor,(id)ecolor.CGColor];
  [pView.layer insertSublayer:layer atIndex:0];

  // creating a tapGestureRecognizer
  [pView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTapInViews:)]];
  [self.view addSubview:pView];

  touched = NO;
}
....
@end

我正在尝试做什么

一旦在 pView 上检测到点击手势,我想将 pView 的高度增加 100.0,但要以动画方式增加。如果 pView 之前被触摸过(也就是说,它的高度已经增加了 100.0),我想将 pView 的高度降低 100.0(也就是说,return将它调整到原来的大小);

我已经知道的

我知道,因为我想更改 pView 的框架,所以我还必须更改附加到 pView 的 CAGradientLayer 的框架(或边界)。因为我想对这些变化进行动画处理,所以我希望这些动画同时发生并具有相同的持续时间。

我知道图层的帧(或边界)只能在动画块内设置动画。

我是做什么的:

这是我测试过的选项:

- (void) handleTapInViews: (nonnull UITapGestureRecognizer *) sender {
  pView = sender.view;

  if (touched) {
    [UIView animateWithDuration:0.4 animations:^{

      pView.frame = CGRectMake(pView.frame.origin.x, pView.frame.origin.y, pView.frame.size.width, pView.frame.size.height - 100.0);
      pView.layer.sublayers[0].frame = pView.bounds;

      [self.view setNeedsLayout];
    } completion:^(BOOL finished) {
      touched = NO;
    }];

  }
  else {
    [UIView animateWithDuration:0.4 animations:^{

      pView.frame = CGRectMake(pView.frame.origin.x, pView.frame.origin.y, pView.frame.size.width, pView.frame.size.height + 100.0);
      pView.layer.sublayers[0].frame = pView.bounds;

      [self.view setNeedsLayout];
    } completion:^(BOOL finished) {
      touched = YES;
    }];

  }

}

这个选项确实有效(即pView的frame和layer的frame都是动画变化的)但是他们不同步;也就是说,layer frame 的变化比 pView frame 的变化稍快(但可以感知)。当pView的高度降低时,这种效果更加明显。

我还阅读了有关 CABasicAnimation 和 CAAnimationGroup 的内容,以便为图层的边界和位置设置动画。在这种情况下,图层的动画也比视图的动画快一点(这是可以察觉的,万一有人询问设置持续时间或其他问题,这不是几秒钟的问题),而且在这种情况下,在动画之后将图层 return 绑定到其原始大小,这不是预期的效果。我已经知道最后这件事可以解决,在动画结束时将新值分配给层,但我肯定不知道我的代码把它放在哪里。

我读到的关于这个其他选项的大部分内容来自这些链接:

link1

link2

link3

link4

无论如何,有人知道我该如何解决这个问题吗?提前致谢。

好吧,我结束了将 Pview 的 backgroundColor 设置为 ecolor = [UIColor colorWithRed:(6/255.0) green: (216/255.0) blue:(69/255.0) alpha:1。这样,我评论说层的动画比视图的动画快的效果现在并不明显。我认为这可能不是正确的答案,但它适合我。