Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/116.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone 创建自定义可设置动画的属性_Iphone_Ios_Uiview_Core Animation - Fatal编程技术网

Iphone 创建自定义可设置动画的属性

Iphone 创建自定义可设置动画的属性,iphone,ios,uiview,core-animation,Iphone,Ios,Uiview,Core Animation,在ui视图上可以更改背景颜色。在UISlideView上,可以更改动画值 您能否将自定义属性添加到自己的UIView子类中,以便为其设置动画 如果我的UIView中有一个CGPath,那么我可以通过更改路径的绘制百分比来设置它的绘制动画 我可以将动画封装到子类中吗 i、 e.我有一个ui视图,带有一个创建圆的CGPath 如果圆不存在,则表示0%。如果圆是满的,则表示100%。我可以通过更改路径的绘制百分比来绘制任何值。我还可以通过设置CGPath的百分比并重新绘制路径来设置更改的动画(在UIV

ui视图上
可以更改背景颜色。在
UISlideView
上,可以更改动画值

您能否将自定义属性添加到自己的
UIView
子类中,以便为其设置动画

如果我的
UIView
中有一个
CGPath
,那么我可以通过更改路径的绘制百分比来设置它的绘制动画

我可以将动画封装到子类中吗

i、 e.我有一个
ui视图
,带有一个创建圆的
CGPath

如果圆不存在,则表示0%。如果圆是满的,则表示100%。我可以通过更改路径的绘制百分比来绘制任何值。我还可以通过设置
CGPath
的百分比并重新绘制路径来设置更改的动画(在UIView子类中)

我可以在
UIView
上设置一些属性(即百分比),以便将更改粘贴到
UIView animateWithDuration
块中,并设置路径百分比更改的动画吗

我希望我已经解释了我想做好的事情

基本上,我想做的就是

[UIView animateWithDuration:1.0
 animations:^{
     myCircleView.percentage = 0.7;
 }
 completion:nil];

并且圆路径将设置为给定百分比的动画。

您必须自己实现百分比部分。可以根据设置的百分比值替代图层绘制代码来绘制cgpath。如果扩展CALayer并实现自定义,请签出和

- (void) drawInContext:(CGContextRef) context
通过覆盖
needsDisplayForKey
(在自定义CALayer类中)可以创建可设置动画的属性,如下所示:

+ (BOOL) needsDisplayForKey:(NSString *) key {
    if ([key isEqualToString:@"percentage"]) {
        return YES;
    }
    return [super needsDisplayForKey:key];
}
当然,您还需要一个名为
百分比
@属性。从现在起,可以使用核心动画设置百分比属性的动画。我也没有使用
[UIView animateWithDuration…]
调用检查它是否工作。这可能有用。但这对我起了作用:

CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"percentage"];
animation.duration = 1.0;
animation.fromValue = [NSNumber numberWithDouble:0];
animation.toValue = [NSNumber numberWithDouble:100];

[myCustomLayer addAnimation:animation forKey:@"animatePercentage"];
哦,要将
yourCustomLayer
myCircleView
一起使用,请执行以下操作:

[myCircleView.layer addSublayer:myCustomLayer];

对于那些像我一样需要更多细节的人:

这个问题有一个很酷的答案

例如,多亏了它,我发现您实际上不需要添加自定义层作为子层(正如@Tom van Zummeren所建议的)。相反,将类方法添加到视图类就足够了:

+ (Class)layerClass
{
    return [CustomLayer class];
}

希望它能帮助别人。

完成Swift 3示例:

有一篇很好的objc文章,详细介绍了它是如何工作的

以及使用相同概念的objc项目:

本质上,当从动画块为对象设置动画时,将调用动作(对于层:),我们可以使用相同的属性(从backgroundColor属性中窃取)启动自己的动画,并为更改设置动画。

@David Rees让我走上正确的轨道,但有一个问题。就我而言 动画完成总是在动画开始后立即返回false

UIView.animate(withDuration: 2, delay: 0, options: .curveEaseInOut, animations: {
    circularProgress.progress = 0.76
}, completion: { finished in
   // finished - always false
})
这就是我的工作方式——动画的动作是在CALayer内部处理的

我还包括了一个小例子,如何使图层具有额外的属性,如“颜色”。 在这种情况下,如果没有复制值的初始值设定项,更改颜色将仅对非动画视图生效。在动画过程中,它将以“默认设置”显示

我在本文中找到了以不同方式处理动画和复制图层特性的方法:

谢谢您的回复。“今晚我要去看一看。”福格迈斯特:嗨,我参加晚会有点晚了。我们希望问:我们如何实现
-(void)drawInContext:(CGContextRef)context
?这是绘制新自定义属性的位置吗?提前谢谢。@Tom在您的示例中,您手动将持续时间设置为1。。。你如何计算出持续时间/曲线/延迟等。。。由UIViewAnimation block提供?感谢您的回复。我今晚去看看,不知道。跟我没关系,你好。您是否尝试过使用
CGAffineTransform
实现
@NSManaged
?Apple的示例代码存在问题。即使禁用动画,它仍会为灯泡设置动画:
[self setOn:!self.on animated:NO]
UIView.animate(withDuration: 2, delay: 0, options: .curveEaseInOut, animations: {
    circularProgress.progress = 0.76
}, completion: { finished in
   // finished - always false
})
public class CircularProgressView: UIView {

    @objc public dynamic var progress: CGFloat {
        get {
            return progressLayer.progress
        }
        set {
            progressLayer.progress = newValue
        }
    }

    fileprivate var progressLayer: CircularProgressLayer {
        return layer as! CircularProgressLayer
    }

    override public class var layerClass: AnyClass {
        return CircularProgressLayer.self
    }
}


/*
* Concepts taken from:
* https://stackoverflow.com/a/37470079
*/
fileprivate class CircularProgressLayer: CALayer {
    @NSManaged var progress: CGFloat
    let startAngle: CGFloat = 1.5 * .pi
    let twoPi: CGFloat = 2 * .pi
    let halfPi: CGFloat = .pi / 2


    var color: UIColor = .red
    // preserve layer properties
    // without this specyfic init, if color was changed to sth else
    // animation would still use .red
    override init(layer: Any) {
        super.init(layer: layer)
        if let layer = layer as? CircularProgressLayer {
            self.color = layer.color
            self.progress = layer.progress
        }
    }

    override init() {
        super.init()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override class func needsDisplay(forKey key: String) -> Bool {
        if key == #keyPath(progress) {
            return true
        }
        return super.needsDisplay(forKey: key)
    }

    override func action(forKey event: String) -> CAAction? {
        if event == #keyPath(CircularProgressLayer.progress) {
            guard let animation = action(forKey: #keyPath(backgroundColor)) as? CABasicAnimation else {
                setNeedsDisplay()
                return nil
            }

            if let presentation = presentation() {
                animation.keyPath = event
                animation.fromValue = presentation.value(forKeyPath: event)
                animation.toValue = nil
            } else {
                return nil
            }

            return animation
        }

        return super.action(forKey: event)
    }

    override func draw(in ctx: CGContext) {
        super.draw(in: ctx)

        UIGraphicsPushContext(ctx)

        //Light Gray
        UIColor.lightGray.setStroke()

        let center = CGPoint(x: bounds.midX, y: bounds.midY)
        let strokeWidth: CGFloat = 4
        let radius = (bounds.size.width / 2) - strokeWidth
        let path = UIBezierPath(arcCenter: center, radius: radius, startAngle: 0, endAngle: twoPi, clockwise: true)
        path.lineWidth = strokeWidth
        path.stroke()

        // Red - default
        self.color.setStroke()

        let endAngle = (twoPi * progress) - halfPi
        let pathProgress = UIBezierPath(arcCenter: center, radius: radius, startAngle: startAngle, endAngle: endAngle , clockwise: true)
        pathProgress.lineWidth = strokeWidth
        pathProgress.lineCapStyle = .round
        pathProgress.stroke()

        UIGraphicsPopContext()
    }
}