我对ios动画相对较新,我相信我为UIView制作动画的方法有问题。
我将从UI截图开始,更精确地描绘我的问题:
每当我向单元格引入新值时,我想为这个最左边的灯泡设置动画,让它看起来像是充满了红色。
这是BadgeView的实现,它基本上是前面提到的最左边的圆圈
class BadgeView: UIView {
var coeff:CGFloat = 0.5
override func drawRect(rect: CGRect) {
let topRect:CGRect = CGRectMake(0, 0, rect.size.width, rect.size.height*(1.0 - self.coeff))
UIColor(red: 249.0/255.0, green: 163.0/255.0, blue: 123.0/255.0, alpha: 1.0).setFill()
UIRectFill(topRect)
let bottomRect:CGRect = CGRectMake(0, rect.size.height*(1-coeff), rect.size.width, rect.size.height*coeff)
UIColor(red: 252.0/255.0, green: 95.0/255.0, blue: 95.0/255.0, alpha: 1.0).setFill()
UIRectFill(bottomRect)
self.layer.cornerRadius = self.frame.height/2.0
self.layer.masksToBounds = true
}
}
这是我实现不均匀填充的方式 - 我引入了我在viewController中修改的系数。
在我的cellForRowAtIndexPath方法中,我尝试使用带回调的自定义按钮设置此形状的动画
let btn:MGSwipeButton = MGSwipeButton(title: "", icon: img, backgroundColor: nil, insets: ins, callback: {
(sender: MGSwipeTableCell!) -> Bool in
print("Convenience callback for swipe buttons!")
UIView.animateWithDuration(4.0, animations:{ () -> Void in
cell.pageBadgeView.coeff = 1.0
let frame:CGRect = cell.pageBadgeView.frame
cell.pageBadgeView.drawRect(frame)
})
return true
})
但它只会打印到控制台
:CGContextSetFillColorWithColor:无效的上下文0x0。如果你想查看回溯,请设置CG_CONTEXT_SHOW_BACKTRACE环境变量。
虽然我很想知道正确的答案和方法,但是出于教育目的,知道这段代码不起作用会很棒。 提前致谢
答案 0 :(得分:9)
问题的错误部分似乎是代码的这一部分:
cell.pageBadgeView.drawRect(frame)
来自UIView drawRect上的Apple docs:
首次显示视图或发生使视图的可见部分无效的事件时,将调用此方法。你永远不应该直接调用这个方法。要使视图的一部分无效,从而导致重绘该部分,请调用setNeedsDisplay或setNeedsDisplayInRect:方法。
因此,如果您将代码更改为:
cell.pageBadgeView.setNeedsDisplay()
您将摆脱错误并正确查看badgeView 已填充。但是这不会动画,因为默认情况下drawRect不可动画。
对于您的问题,最简单的解决方法是让BadgeView拥有填充颜色的内部视图。我将重构BadgeView:
class BadgeView: UIView {
private let fillView = UIView(frame: CGRectZero)
private var coeff:CGFloat = 0.5 {
didSet {
// Make sure the fillView frame is updated everytime the coeff changes
updateFillViewFrame()
}
}
// Only needed if view isn't created in xib or storyboard
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
// Only needed if view isn't created in xib or storyboard
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
}
override func awakeFromNib() {
setupView()
}
private func setupView() {
// Setup the layer
layer.cornerRadius = bounds.height/2.0
layer.masksToBounds = true
// Setup the unfilled backgroundColor
backgroundColor = UIColor(red: 249.0/255.0, green: 163.0/255.0, blue: 123.0/255.0, alpha: 1.0)
// Setup filledView backgroundColor and add it as a subview
fillView.backgroundColor = UIColor(red: 252.0/255.0, green: 95.0/255.0, blue: 95.0/255.0, alpha: 1.0)
addSubview(fillView)
// Update fillView frame in case coeff already has a value
updateFillViewFrame()
}
private func updateFillViewFrame() {
fillView.frame = CGRectMake(0, bounds.height*(1-coeff), bounds.width, bounds.height*coeff)
}
// Setter function to set the coeff animated. If setting it not animated isn't necessary at all, consider removing this func and animate updateFillViewFrame() in coeff didSet
func setCoeff(coeff: CGFloat, animated: Bool) {
if animated {
UIView.animateWithDuration(4.0, animations:{ () -> Void in
self.coeff = coeff
})
} else {
self.coeff = coeff
}
}
}
在您的按钮回调中,您只需执行以下操作:
cell.pageBadgeView.setCoeff(1.0, animated: true)
答案 1 :(得分:3)
试试这个游乐场代码
import UIKit
import CoreGraphics
var str = "Hello, playground"
class BadgeView: UIView {
var coeff:CGFloat = 0.5
func drawCircleInView(){
// Set up the shape of the circle
let size:CGSize = self.bounds.size;
let layer = CALayer();
layer.frame = self.bounds;
layer.backgroundColor = UIColor.blue().cgColor
let initialRect:CGRect = CGRect.init(x: 0, y: size.height, width: size.width, height: 0)
let finalRect:CGRect = CGRect.init(x: 0, y: size.height/2, width: size.width, height: size.height/2)
let sublayer = CALayer()
sublayer.frame = initialRect
sublayer.backgroundColor = UIColor.orange().cgColor
sublayer.opacity = 0.5
let mask:CAShapeLayer = CAShapeLayer()
mask.frame = self.bounds
mask.path = UIBezierPath(ovalIn: self.bounds).cgPath
mask.fillColor = UIColor.black().cgColor
mask.strokeColor = UIColor.yellow().cgColor
layer.addSublayer(sublayer)
layer.mask = mask
self.layer.addSublayer(layer)
let boundsAnim:CABasicAnimation = CABasicAnimation(keyPath: "bounds")
boundsAnim.toValue = NSValue.init(cgRect:finalRect)
let anim = CAAnimationGroup()
anim.animations = [boundsAnim]
anim.isRemovedOnCompletion = false
anim.duration = 3
anim.fillMode = kCAFillModeForwards
sublayer.add(anim, forKey: nil)
}
}
var badgeView:BadgeView = BadgeView(frame:CGRect.init(x: 50, y: 50, width: 50, height: 50))
var window:UIWindow = UIWindow(frame: CGRect.init(x: 0, y: 0, width: 200, height: 200))
window.backgroundColor = UIColor.red()
badgeView.backgroundColor = UIColor.green()
window.becomeKey()
window.makeKeyAndVisible()
window.addSubview(badgeView)
badgeView.drawCircleInView()
答案 2 :(得分:0)
对上述代码的更多修改,上面代码中缺少定位点代码
```
var str = "Hello, playground"
class BadgeView: UIView {
var coeff:CGFloat = 0.7
func drawCircleInView(){
// Set up the shape of the circle
let size:CGSize = self.bounds.size;
let layerBackGround = CALayer();
layerBackGround.frame = self.bounds;
layerBackGround.backgroundColor = UIColor.blue.cgColor
self.layer.addSublayer(layerBackGround)
let initialRect:CGRect = CGRect.init(x: 0, y: size.height , width: size.width, height: 0)
let finalRect:CGRect = CGRect.init(x: 0, y: 0, width: size.width, height: size.height)
let sublayer = CALayer()
//sublayer.bounds = initialRect
sublayer.frame = initialRect
sublayer.anchorPoint = CGPoint(x: 0.5, y: 1)
sublayer.backgroundColor = UIColor.orange.cgColor
sublayer.opacity = 1
let mask:CAShapeLayer = CAShapeLayer()
mask.frame = self.bounds
mask.path = UIBezierPath(ovalIn: self.bounds).cgPath
mask.fillColor = UIColor.black.cgColor
mask.strokeColor = UIColor.yellow.cgColor
layerBackGround.addSublayer(sublayer)
layerBackGround.mask = mask
self.layer.addSublayer(layerBackGround)
let boundsAnim:CABasicAnimation = CABasicAnimation(keyPath: "bounds")
boundsAnim.toValue = NSValue.init(cgRect:finalRect)
let anim = CAAnimationGroup()
anim.animations = [boundsAnim]
anim.isRemovedOnCompletion = false
anim.duration = 1
anim.fillMode = kCAFillModeForwards
sublayer.add(anim, forKey: nil)
}