iOS Animate Mask Over UIImage

前端 未结 1 459
后悔当初
后悔当初 2021-01-01 04:35

I am using Swift 1.2 and my goal is to animate an image mask over a static UIImage. What I have implemented is a swift version of masking an image that I originally found in

相关标签:
1条回答
  • 2021-01-01 05:13

    You do indeed want to use a CALayer - or rather, a CAShapeLayer.

    You can create a CAShapeLayer and install it as as the mask on another layer.

    You can create a CAAnimation that animates changes to the shape layer's path, or you can animate changes to the layer's strokeStart and/or strokeEnd properties.

    If you animate the path, the one rule you want to follow is to make sure that the starting and ending path have the same number and type of control points. Otherwise the animation is "undefined", and the results can be very strange.

    I have a development blog post that outlines how it's done:

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

    It's primarily about using CAAnimationGroups, but it also includes a working example of animating changes to a CAShapeLayer that's used as the mask of an image view's layer.

    Below is a GIF of the mask animation that it creates - a "clock wipe" that shows and hides an image view:

    enter image description here

    Unfortunately it's written in Objective-C, but the Core Animation calls are nearly identical in Swift. Let me know if you have any problems figuring out how to adapt it.

    The meat of the animation code is this method:

    - (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"];
    }
    

    I have another blog entry that IS in Swift that shows how to create and animate a pie chart using a CAShapeLayer. That project animates shape, not a mask, but the only real difference is whether you install the shape layer as a regular content layer or as a mask on another layer like the backing layer of an image view.

    You can check out that project at this link:

    http://wareto.com/swift-piecharts

    0 讨论(0)
提交回复
热议问题