如何在UITableViewCell内部居中自定义CAShapeLayer?

时间:2019-06-14 07:51:49

标签: ios swift uitableview swift4 swift5

我已经使用CAShapeLayer创建了一个自定义的循环进度栏。我可以使用UIView轻松将其居中放置在任何view.center中,但是我需要将其居中放置在UITableView单元中,这就是我得到的:

如果您查看该图像,上方的圆圈会正确显示CAShapeLayer内的同一UIView

我已经尝试过view.center, [x: view.frame.width /2, y :view.frame.height / 2 ] 我还尝试将UIView内的Cell居中,并将CAShapeLayer添加到居中的视图中。...不起作用。

let center = CGPoint(x: self.frame.width/2, y: self.frame.height/2) 
let circularPath = UIBezierPath(arcCenter: .zero, radius: 80, startAngle: 0, endAngle: CGFloat.pi * 2, clockwise: true)
pulsatingLayer.position = center

完整代码:

import UIKit

class CurrentGACell: UITableViewCell {

    let shapeLayer = CAShapeLayer()

    var pulsatingLayer: CAShapeLayer!

    let percentageLabel: UILabel = {
        var label = UILabel()
        label.text = "Start"
        label.textAlignment = .center
        label.font = UIFont(name: "AvenirNext-DemiBold", size: 30)
        label.backgroundColor = UIColor.clear
        return label
    }()

    @IBOutlet weak var mainView: UIView!

    override func awakeFromNib() {
        super.awakeFromNib()
        setupNotificationObserver()

        let center = self.contentView.center //CGPoint(x: contentView.frame.width/2, y: contentView.frame.height/2) //mainView.center
        let circularPath = UIBezierPath(arcCenter: .zero, radius: 80, startAngle: 0, endAngle: CGFloat.pi * 2, clockwise: true)

        //pulsating
        pulsatingLayer = CAShapeLayer()
        pulsatingLayer.path = circularPath.cgPath
        pulsatingLayer.fillColor = UIColor.AppColors.Blue.withAlphaComponent(0.2).cgColor
        pulsatingLayer.strokeColor = UIColor.clear.cgColor
        pulsatingLayer.lineWidth = 10
        pulsatingLayer.lineCap = .round
        pulsatingLayer.position = center
        self.contentView.layer.addSublayer(pulsatingLayer)
        animatePulsatingLayer()

        //trackLayer
        let trackLayer = CAShapeLayer()
        trackLayer.path = circularPath.cgPath
        trackLayer.fillColor = UIColor.white.cgColor
        trackLayer.strokeColor = UIColor.AppColors.Blue.withAlphaComponent(0.2).cgColor
        trackLayer.lineWidth = 10
        trackLayer.lineCap = .round
        trackLayer.position = center
        self.contentView.layer.addSublayer(trackLayer)

        //shapeLayer
        shapeLayer.path = circularPath.cgPath
        shapeLayer.fillColor = UIColor.white.cgColor
        shapeLayer.strokeColor = UIColor.AppColors.Blue.cgColor
        shapeLayer.lineWidth = 10
        shapeLayer.strokeEnd = 0
        shapeLayer.lineCap = .round
        shapeLayer.position = center
        shapeLayer.transform = CATransform3DMakeRotation(-CGFloat.pi/2, 0, 0, 1)
        self.contentView.layer.addSublayer(shapeLayer)

        self.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleTap)))

        self.contentView.addSubview(percentageLabel)
        percentageLabel.frame = CGRect(x: 0, y: 0, width: 500, height: 100)
        percentageLabel.center = center

    }

    @objc private func handleTap() {
        //beginDownloading()
        animateCircle()
    }

    fileprivate func animateCircle() {
        print("animating....")
        let basicAnimation = CABasicAnimation(keyPath: "strokeEnd")
        basicAnimation.toValue = 0.65
        basicAnimation.duration = 1
        basicAnimation.fillMode = CAMediaTimingFillMode.forwards
        basicAnimation.isRemovedOnCompletion = false

        percentageLabel.text = "29w + 3d"

        shapeLayer.add(basicAnimation, forKey: "urSoBasic")
    }

    private func animatePulsatingLayer() {
        let animation = CABasicAnimation(keyPath: "transform.scale")
        animation.toValue = 1.2
        animation.duration = 1
        animation.autoreverses = true
        animation.repeatCount = Float.infinity
        animation.timingFunction = CAMediaTimingFunction(name: .easeOut)
        pulsatingLayer.add(animation, forKey: "pulsating")
    }

    private func setupNotificationObserver() {
        NotificationCenter.default.addObserver(self, selector: #selector(handleEnterForegroung), name: UIApplication.willEnterForegroundNotification, object: nil)
    }
    @objc func handleEnterForegroung() {
        animatePulsatingLayer()
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}

2 个答案:

答案 0 :(得分:0)

您需要将所有代码添加到layoutSubviews方法中。

let shapeLayer = CAShapeLayer()
override func layoutSubviews() {
    let circularPath = UIBezierPath(arcCenter: .zero, radius: 25, startAngle: 0, endAngle: CGFloat.pi * 2, clockwise: true)
    shapeLayer.path = circularPath.cgPath
    shapeLayer.strokeColor = UIColor.blue.cgColor
    shapeLayer.fillColor = UIColor.gray.cgColor
    shapeLayer.lineWidth = 1.0
    shapeLayer.position = self.contentView.center
    if !self.contentView.layer.sublayers!.contains(shapeLayer){
        self.layer.addSublayer(shapeLayer)
    }
}

OR

您可以使用UIScreen的静态值

override func awakeFromNib() {
    super.awakeFromNib()
    let point = CGPoint.init(x: UIScreen.main.bounds.width/2, y: self.contentView.frame.height/2)
    let circularPath = UIBezierPath(arcCenter: .zero, radius: 25, startAngle: 0, endAngle: CGFloat.pi * 2, clockwise: true)
    let shapeLayer = CAShapeLayer()
    shapeLayer.path = circularPath.cgPath
    shapeLayer.strokeColor = UIColor.blue.cgColor
    shapeLayer.fillColor = UIColor.gray.cgColor
    shapeLayer.lineWidth = 1.0
    shapeLayer.position = point
    self.layer.addSublayer(shapeLayer)
}

注意:

由于在帧渲染之前添加了一个图层,所以得到了不可预测的结果。

答案 1 :(得分:-1)

将依赖于.contentView框架的代码移动到layoutSubviews()。只有这样,才能保证您的CurrentGACell具有正确的框架。

类似的东西:

let shapeLayer = CAShapeLayer()
let trackLayer = CAShapeLayer()
var pulsatingLayer: CAShapeLayer!

func layoutSubviews() {
   super.layoutSubviews()
   let center = contentView.center
   pulsatingLayer.position = center
   trackLayer.position = center
   shapeLayer.position = center
   percentageLabel.center = center
}