使用蒙版显示/隐藏带动画的视图

时间:2015-03-11 14:54:55

标签: ios ios8 calayer mask bounds

我正在尝试使用遮罩来隐藏和显示视图,但由于某种原因我无法正常工作。

我真的很困惑我是否应该为蒙版的框架/边界/路径设置动画。

这是我的代码,用于显示按钮操作的视图" GO":

- (IBAction)go:(id)sender
{
    [UIView animateWithDuration:3.0 animations:^{

        self.testView.layer.mask.bounds = self.testView.layer.bounds;
    }];
}

- (void)viewDidLoad
{
    [super viewDidLoad];

    CGRect rect = CGRectMake(0, 0, self.testView.bounds.size.width, 0);
    CGPathRef path = CGPathCreateWithRect(rect, NULL);

    CAShapeLayer *shapeLayer = [CAShapeLayer layer];
    shapeLayer.path = path;

    self.testView.layer.mask = shapeLayer;
    self.testView.layer.mask.bounds = rect;
}

谢谢!

2 个答案:

答案 0 :(得分:1)

您正在更改掩码的bounds,而不是path。您确实需要更改path的{​​{1}}。理论上你可以用mask来做到这一点,但我个人觉得在设置动画路径(特别是掩码的动画)时非常不稳定。

如果可以的话,我会完全退出掩码,只需设置CABasicAnimation的帧,使其不可见(例如,高度为零),然后使用基于块的方式设置该帧的更改动画testView UIView。 (注意,如果使用自动布局,则可以设置animateWithDuration已更改约束的动画。

如果您确实需要使用setNeedsLayout掩码,可以在掩码CAShapeLayer上使用CABAsicAnimation密钥animateWithKeyPath尝试path

就个人而言,当动画改变路径时,我会使用显示链接,例如类似的东西:

CAShapeLayer

我的- (IBAction)didTapButton:(UIBarButtonItem *)sender { [AnimationDisplayLink animateWithDuration:3.0 animationHandler:^(CGFloat percent) { self.mask.path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, self.testView.bounds.size.width, self.testView.bounds.size.height * percent)].CGPath; } completionHandler:nil]; } 定义如下:

AnimationDisplayLink

答案 1 :(得分:0)

Rob的回答的快速版本

import UIKit

typealias PercentBasedAnimationHandler = ((_ percent: CGFloat) -> Void)
typealias AnimationCompletionHandler = (() -> Void)

class AnimationDisplayLink: NSObject {
var animationDuration: CGFloat = 0.3

var animationHandler: PercentBasedAnimationHandler!
var completionHandler: AnimationCompletionHandler!

var startTime: CFAbsoluteTime!

var displayLink: CADisplayLink!

static func animateWith(duration: CGFloat, animationHanlder: @escaping PercentBasedAnimationHandler, completionHandler: @escaping AnimationCompletionHandler) -> AnimationDisplayLink {

    let handler = AnimationDisplayLink()
    handler.animationDuration = duration
    handler.animationHandler = animationHanlder
    handler.completionHandler = completionHandler
    handler.startAnimation()

    return handler
}

func startAnimation() {
    self.startTime = CFAbsoluteTimeGetCurrent()
    self.displayLink = CADisplayLink(target: self, selector: #selector(hanldeDisplayLink(displayLink:)))
    self.displayLink.add(to: RunLoop.main, forMode: .commonModes)
}

func stopAnimation() {
    self.displayLink.invalidate()
    self.displayLink = nil
}

@objc func hanldeDisplayLink(displayLink: CADisplayLink) {
    let elapsed = CFAbsoluteTimeGetCurrent() - self.startTime
    let percent = CGFloat(elapsed) / animationDuration

    if percent >= 1.0 {
        stopAnimation()
        self.animationHandler(1.0)
        self.completionHandler()
    } else {
        self.animationHandler(percent)
    }
}
}