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()
}
}