无法让自定义活动指示器设置动画
Posted
技术标签:
【中文标题】无法让自定义活动指示器设置动画【英文标题】:Can't get custom activity indicator to animate 【发布时间】:2020-06-13 12:35:48 【问题描述】:我将原本在 Objc file 中的 custom activity indicator 重写为 Swift。活动指示器出现在场景中,但动画没有出现。
我需要一些帮助来弄清楚为什么动画没有出现:
vc:
class ViewController: UIViewController
fileprivate lazy var customActivityView: CustomActivityView =
let customActivityView = CustomActivityView()
customActivityView.translatesAutoresizingMaskIntoConstraints = false
customActivityView.delegate = self
customActivityView.numberOfCircles = 3
customActivityView.radius = 20
customActivityView.internalSpacing = 3
customActivityView.startAnimating()
return customActivityView
()
override func viewDidLoad()
super.viewDidLoad()
view.backgroundColor = .white
setAnchors()
fileprivate func setAnchors()
view.addSubview(customActivityView)
customActivityView.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
customActivityView.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
customActivityView.widthAnchor.constraint(equalToConstant: 100).isActive = true
customActivityView.heightAnchor.constraint(equalToConstant: 100).isActive = true
extension ViewController: CustomActivityViewDelegate
func activityIndicatorView(activityIndicatorView: CustomActivityView, circleBackgroundColorAtIndex index: Int) -> UIColor
let red = CGFloat(Double((arc4random() % 256)) / 255.0)
let green = CGFloat(Double((arc4random() % 256)) / 255.0)
let blue = CGFloat(Double((arc4random() % 256)) / 255.0)
let alpha: CGFloat = 1
return UIColor(red: red, green: green, blue: blue, alpha: alpha)
Swift 文件:
import UIKit
protocol CustomActivityViewDelegate: class
func activityIndicatorView(activityIndicatorView: CustomActivityView, circleBackgroundColorAtIndex index: Int) -> UIColor
class CustomActivityView: UIView
var numberOfCircles: Int = 0
var internalSpacing: CGFloat = 0
var radius: CGFloat = 0
var delay: CGFloat = 0
var duration: CFTimeInterval = 0
var defaultColor = UIColor.systemPink
var isAnimating = false
weak var delegate: CustomActivityViewDelegate?
override init(frame: CGRect)
super.init(frame: frame)
setupDefaults()
required init?(coder: NSCoder)
super.init(coder: coder)
setupDefaults()
fatalError("init(coder:) has not been implemented")
func setupDefaults()
self.translatesAutoresizingMaskIntoConstraints = false
numberOfCircles = 5
internalSpacing = 5
radius = 10
delay = 0.2
duration = 0.8
func createCircleWithRadius(radius: CGFloat, color: UIColor, positionX: CGFloat) -> UIView
let circle = UIView(frame: CGRect(x: positionX, y: 0, width: radius * 2, height: radius * 2))
circle.backgroundColor = color
circle.layer.cornerRadius = radius
circle.translatesAutoresizingMaskIntoConstraints = false;
return circle
func createAnimationWithDuration(duration: CFTimeInterval, delay: CGFloat) -> CABasicAnimation
let anim: CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation")
anim.fromValue = 0.0
anim.toValue = 1.0
anim.autoreverses = true
anim.duration = duration
anim.isRemovedOnCompletion = false
anim.beginTime = CACurrentMediaTime()+Double(delay)
anim.repeatCount = .infinity
anim.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
return anim;
func addCircles()
for i in 0..<numberOfCircles
var color: UIColor?
color = delegate?.activityIndicatorView(activityIndicatorView: self, circleBackgroundColorAtIndex: i)
let circle = createCircleWithRadius(radius: radius,
color: ((color == nil) ? self.defaultColor : color)!,
positionX: CGFloat(i) * ((2 * self.radius) + self.internalSpacing))
circle.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
circle.layer.add(self.createAnimationWithDuration(duration: self.duration,
delay: CGFloat(i) * self.delay), forKey: "scale")
self.addSubview(circle)
func removeCircles()
self.subviews.forEach( $0.removeFromSuperview() )
@objc func startAnimating()
if !isAnimating
addCircles()
self.isHidden = false
isAnimating = true
@objc func stopAnimating()
if isAnimating
removeCircles()
self.isHidden = true
isAnimating = false
func intrinsicContentSize() -> CGSize
let width: CGFloat = (CGFloat(self.numberOfCircles) * ((2 * self.radius) + self.internalSpacing)) - self.internalSpacing
let height: CGFloat = radius * 2
return CGSize(width: width, height: height)
func setNumberOfCircles(numberOfCircles: Int)
self.numberOfCircles = numberOfCircles
self.invalidateIntrinsicContentSize()
func setRadius(radius: CGFloat)
self.radius = radius
self.invalidateIntrinsicContentSize()
func setInternalSpacing(internalSpacing: CGFloat)
self.internalSpacing = internalSpacing
self.invalidateIntrinsicContentSize()
【问题讨论】:
【参考方案1】:我为动画使用了错误的关键路径:
我用过
// incorrect
let anim: CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation")
但我应该用过
// correct
let anim: CABasicAnimation = CABasicAnimation(keyPath: "transform.scale")
【讨论】:
以上是关于无法让自定义活动指示器设置动画的主要内容,如果未能解决你的问题,请参考以下文章