Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
210 views
in Technique[技术] by (71.8m points)

swift - Setting toValue for CAShapeLayer animation from UICollectionView cellForItemAt indexPath

I have the following parts: - My main view is a UIViewController with a UICollectionView - The cell for the UICollectionView - A subclass of the UIView to build a CAShapeLayer with an CABasicAnimation

In my main view I have a UICollectionView which renders a bunch of cells with labels etc. It also is showing a progress graph.

In my subclass ProgressCirclePath() I am drawing a CAShapeLayer which is acting as the progress graph rendered in each cell of my UICollectionView.

I have been able to pass data to each cell, e.g. the labels as well as the CAShapeLayer strokeEnd values.

Everything is fine until I try to add a CABasicAnimation to my path. In this case I am not able to set the value for the animations toValue. Testing using the print console reveals that the value is available in my UICollectionView but not in the animation block in my subClass (which is where it simply returns nil). I have tried simply setting the toValue as well as creating a variable within my ProgressCirlePath and setting it from the UICollectionView. Neither worked.

I'd appreciate any hints on why this is happening and how to solve this. Thanks!!

Within my UICollectionView:

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
      let cell = decksCollectionView.dequeueReusableCell(withReuseIdentifier: "DeckCell", for: indexPath) as! DeckCell

  cell.creatorLabel.text = deckCellCreator[indexPath.item]
  cell.titleLabel.text = deckCellTitle[indexPath.item]
  cell.progressLabel.text = "(deckCellCompletionPercentage[indexPath.item])%"

  cell.progressGraphView.animation.toValue = CGFloat(deckCellCompletionPercentage[indexPath.item])/100

  return cell
}

The setup within my cell class:

let progressGraphView: ProgressCirclePath = {
    let circlePath = ProgressCirclePath(frame: CGRect(x:0, y:0, width: 86, height: 86))
    circlePath.progressLayer.position = circlePath.center
    circlePath.progressBackgroundLayer.position = circlePath.center
    circlePath.translatesAutoresizingMaskIntoConstraints = false
    return circlePath
}()

And here my ProgressCirclePath()

class ProgressCirclePath: UIView {
let progressLayer = CAShapeLayer()
let progressBackgroundLayer = CAShapeLayer()
let animation = CABasicAnimation(keyPath: "strokeEnd")
//    var percentageValue = CGFloat()


override init(frame: CGRect) {
    super.init(frame: frame)

    layer.addSublayer(progressBackgroundLayer)
    layer.addSublayer(progressLayer)

    let circularPath = UIBezierPath(arcCenter: .zero, radius: 43, startAngle: 0, endAngle: 2*CGFloat.pi, clockwise: true)

    progressBackgroundLayer.path = circularPath.cgPath
    progressBackgroundLayer.lineWidth = 10
    progressBackgroundLayer.strokeStart = 0
    progressBackgroundLayer.strokeEnd = 1
    progressBackgroundLayer.strokeColor = UIColor(red: 221/255.0, green: 240/255.0, blue: 226/255.0, alpha: 1.0).cgColor
    progressBackgroundLayer.fillColor = UIColor.clear.cgColor
    progressBackgroundLayer.transform = CATransform3DMakeRotation(-CGFloat.pi/2, 0, 0, 1)

    progressLayer.path = circularPath.cgPath
    progressLayer.lineWidth = 10
    progressLayer.lineCap = kCALineCapRound
    progressLayer.strokeColor = UIColor(red: 72/255.0, green: 172/255.0, blue: 104/255.0, alpha: 1.0).cgColor
    progressLayer.fillColor = UIColor.clear.cgColor
    progressLayer.transform = CATransform3DMakeRotation(-CGFloat.pi/2, 0, 0, 1)


    animation.duration = 1
    animation.fromValue = 0
    // animation.toValue = percentageValue
    animation.fillMode = kCAFillModeForwards
    animation.isRemovedOnCompletion = false
    progressLayer.add(animation, forKey: "animateGraph")
    print("animation.toValue (animation.toValue)")
}

required init?(coder aDecoder: NSCoder) {
    fatalError("has not been implemented")
}

}

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You're handling the injection of data and animation too early in the lifecycle of the custom view. Instead of handling them in the object's initializer, move them to a later and more appropriate method, such as layoutSubviews:

override open func layoutSubviews() {
    super.layoutSubviews()

    // handle post-init stuff here, like animations and passing in data
    // when it doesn't get passed in on init

}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...