UIImage上的iOS Animate Mask

时间:2015-04-25 01:45:21

标签: ios swift animation uiimage

我正在使用Swift 1.2,我的目标是在静态UIImage上设置图像蒙版的动画。我实现的是一个快速版本的掩盖我最初在Objective-C中找到的图像。

func maskImage(image: UIImage, mask: UIImage) -> UIImage! {

    let maskRef = mask.CGImage;

    let mask = CGImageMaskCreate(
        CGImageGetWidth(maskRef),
        CGImageGetHeight(maskRef),
        CGImageGetBitsPerComponent(maskRef),
        CGImageGetBitsPerPixel(maskRef),
        CGImageGetBytesPerRow(maskRef),
        CGImageGetDataProvider(maskRef), nil, false);

    let masked = CGImageCreateWithMask(image.CGImage, mask);
    let retImage = UIImage(CGImage: masked);
    return retImage;
}

效果很好!然而,将其付诸实践是我的挑战。

有没有办法迭代地应用具有不同水平偏移的掩码或更好的方法来完全解决这个问题 - 也许使用CALayer实现?

感谢您的帮助!

编辑:根据发布的答案,我补充说:

    let image = UIImage(named: "clouds");

    let imageView = UIImageView(image: image);
    let layer = CALayer();
    layer.contents = UIImage(named: "alpha-mask")?.CGImage;
    layer.bounds = CGRectMake(0, 0, image.size.width, image.size.height);

    // For other folks learning, this did not work
    //let animation = CABasicAnimation(keyPath: "bounds.origin.x");

    // This does work
    let animation = CABasicAnimation(keyPath: "position.x");

    animation.duration = 2;
    animation.delegate = self;
    animation.fillMode = kCAFillModeForwards;
    animation.repeatCount = 0;
    animation.fromValue = 0.0;
    animation.toValue = image.size.width;
    animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear);
    animation.removedOnCompletion = false;

    layer.addAnimation(animation, forKey: "transform");

    imageView.layer.mask = layer;

    self.addSubview(imageView);

我能够正确看到alpha蒙版,但动画不起作用。有什么想法吗?

编辑:我修改了上面的代码并且它有效!我需要创建keyPath position.x.见上文

1 个答案:

答案 0 :(得分:10)

您确实想要使用CALayer - 或者更确切地说,使用CAShapeLayer。

您可以创建一个CAShapeLayer并将其作为掩码安装在另一个图层上。

您可以创建一个动画更改形状图层路径的CAAnimation,也可以为图层的strokeStart和/或strokeEnd属性设置动画。

如果为路径设置动画,则要遵循的一条规则是确保起始路径和结束路径具有相同数量和类型的控制点。否则动画是“未定义的”,结果可能非常奇怪。

我有一篇开发博客文章,概述了它是如何完成的:

http://wareto.com/using-core-animation-groups-to-create-animation-sequences-2

它主要是关于使用CAAnimationGroups,但它还包含一个动画示例,用于动画对CAShapeLayer的更改,该CAShapeLayer用作图像视图图层的蒙版。

下面是它创建的蒙版动画的GIF - 显示和隐藏图像视图的“时钟擦除”:

enter image description here

不幸的是,它是用Objective-C编写的,但核心动画调用在Swift中几乎完全相同。如果你有任何问题想知道如何适应它,请告诉我。

动画代码的核心就是这个方法:

- (IBAction)doMaskAnimation:(id)sender;
{

  waretoLogoLarge.hidden = FALSE;//Show the image view

  //Create a shape layer that we will use as a mask for the waretoLogoLarge image view
  CAShapeLayer *maskLayer = [CAShapeLayer layer];

  CGFloat maskHeight = waretoLogoLarge.layer.bounds.size.height;
  CGFloat maskWidth = waretoLogoLarge.layer.bounds.size.width;

  CGPoint centerPoint;
  centerPoint = CGPointMake( maskWidth/2, maskHeight/2);

  //Make the radius of our arc large enough to reach into the corners of the image view.
  CGFloat radius = sqrtf(maskWidth * maskWidth + maskHeight * maskHeight)/2;

  //Don't fill the path, but stroke it in black.
  maskLayer.fillColor = [[UIColor clearColor] CGColor];
  maskLayer.strokeColor = [[UIColor blackColor] CGColor];

  maskLayer.lineWidth = radius; //Make the line thick enough to completely fill the circle we're drawing

  CGMutablePathRef arcPath = CGPathCreateMutable();

  //Move to the starting point of the arc so there is no initial line connecting to the arc
  CGPathMoveToPoint(arcPath, nil, centerPoint.x, centerPoint.y-radius/2);

  //Create an arc at 1/2 our circle radius, with a line thickess of the full circle radius
  CGPathAddArc(arcPath,
               nil,
               centerPoint.x,
               centerPoint.y,
               radius/2,
               3*M_PI/2,
               -M_PI/2,
               YES);

  maskLayer.path = arcPath;

  //Start with an empty mask path (draw 0% of the arc)
  maskLayer.strokeEnd = 0.0;

  CFRelease(arcPath);

  //Install the mask layer into out image view's layer.
  waretoLogoLarge.layer.mask = maskLayer;

  //Set our mask layer's frame to the parent layer's bounds.
  waretoLogoLarge.layer.mask.frame = waretoLogoLarge.layer.bounds;

  //Create an animation that increases the stroke length to 1, then reverses it back to zero.
  CABasicAnimation *swipe = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
  swipe.duration = 2;
  swipe.delegate = self;
  [swipe setValue: theBlock forKey: kAnimationCompletionBlock];

  swipe.timingFunction = [CAMediaTimingFunction 
    functionWithName:kCAMediaTimingFunctionLinear];
  swipe.fillMode = kCAFillModeForwards;
  swipe.removedOnCompletion = NO;
  swipe.autoreverses = YES;

  swipe.toValue = [NSNumber numberWithFloat: 1.0];

  [maskLayer addAnimation: swipe forKey: @"strokeEnd"];
}

我在Swift中有另一个博客条目 IS ,它显示了如何使用CAShapeLayer创建饼图并为其设置动画。该项目为形状设置动画,而不是蒙版,但唯一真正的区别在于您是将形状图层安装为常规内容图层还是作为图像视图背衬层等其他图层上的蒙版。

您可以通过以下链接查看该项目:

http://wareto.com/swift-piecharts