【问题标题】:why isnt my CaLayer showing up on top of the UIView?为什么我的 CaLayer 没有显示在 UIView 之上?
【发布时间】:2021-08-03 08:13:12
【问题描述】:

我想使用名为LoadingViewUIViewUIViewController 上显示一个视图。但是,每当我尝试使用以下代码时,只会出现 UIView 而没有 CALayer

理想情况下,当调用startLoading() 时,此代码会导致出现UIView。然后CALayer 将被添加到UIView 中,它将是一个围绕视图中心旋转的圆圈。我可以改变什么来让这个CALayerUIView 上以正确的方式显示?

class LoadingView: UIView {
    
    let circleLayer = CAShapeLayer()

    init() {
        super.init(frame: .zero)
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func startLoading() {
        let size = 50
        if let topView = UIApplication.topViewController()?.view {
            topView.addSubview(self)
            translatesAutoresizingMaskIntoConstraints = false
            NSLayoutConstraint.activate([
                self.centerYAnchor.constraint(equalTo: topView.centerYAnchor),
                self.centerXAnchor.constraint(equalTo: topView.centerXAnchor),
                self.widthAnchor.constraint(equalToConstant: CGFloat(size)),
                self.heightAnchor.constraint(equalToConstant: CGFloat(size)),
            ])
            self.layer.cornerRadius = frame.height/3
            addShadow(shadowColor: UIColor.label.cgColor, shadowOffset: CGSize(width: 0, height: 0), shadowOpacity: 0.3, shadowRadius: 2)
            backgroundColor = .secondarySystemBackground
            animateCircle(duration: .infinity)
        }
    }
    
    private func animateCircle(duration: TimeInterval) {
        let circlePath = UIBezierPath(arcCenter: CGPoint(x: self.frame.midX, y: self.frame.midY), radius: (frame.size.width), startAngle: 0.0, endAngle: CGFloat(Double.pi*2), clockwise: true)

        // Setup the CAShapeLayer with the path, colors, and line width
        circleLayer.path = circlePath.cgPath
        circleLayer.fillColor = UIColor.clear.cgColor
        circleLayer.strokeColor = Constants.Colors.mainBlue?.cgColor
        circleLayer.lineWidth = 1.0

        // Don't draw the circle initially
        circleLayer.strokeEnd = 0.0

        // Add the circleLayer to the view's layer's sublayers
        self.layer.addSublayer(circleLayer)
        // We want to animate the strokeEnd property of the circleLayer
        let animation = CABasicAnimation(keyPath: "strokeEnd")
        animation.duration = duration
        animation.fromValue = 0
        animation.toValue = 1
        animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut)
        circleLayer.strokeEnd = 0
        circleLayer.add(animation, forKey: "animateCircle")
        
        let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
        rotationAnimation.fromValue = 0.0
        rotationAnimation.toValue = Double.pi*3
        rotationAnimation.duration = duration
        rotationAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn)
        circleLayer.add(rotationAnimation, forKey: nil)
        
        let fadeAnimation = CABasicAnimation(keyPath: "opacity")
        fadeAnimation.fromValue = 1
        fadeAnimation.toValue = 0
        fadeAnimation.duration = duration
        fadeAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn)
        circleLayer.add(fadeAnimation, forKey: nil)
    }
    
    func stopLoading() {
        self.removeFromSuperview()
    }
    
}

【问题讨论】:

    标签: ios swift xcode uiview calayer


    【解决方案1】:

    我注意到您没有设置 circleLayer 的 frame。 尝试将其设置为您的视图。

    【讨论】:

      【解决方案2】:

      有几个地方出了问题:

      1. 需要准确设置CALayer的frame/bounds。请记住,这可能会从最初的位置发生变化。例如,在我的第一个测试中,该层认为它是一个0x0 矩形。

      2. 曲线的路径要正确设置(与#1有关)

      3. 您当前的.infinity 时间会使动画需要无限时间才能完成。我认为您想要的是一个需要一定时间并无限重复重复的动画。

      我现在可能忘记了另一个变化,但这应该让你开始:

      
      class LoadingView: UIView {
          
          let circleLayer = CAShapeLayer()
          
          private var circlePath : UIBezierPath = .init()
          let size : CGFloat = 50
          
          init() {
              super.init(frame: .zero)
          }
          
          required init?(coder: NSCoder) {
              fatalError("init(coder:) has not been implemented")
          }
          
          func startLoading() {
              if let topView = UIApplication.topViewController()?.view {
                  topView.addSubview(self)
                  translatesAutoresizingMaskIntoConstraints = false
                  NSLayoutConstraint.activate([
                      self.centerYAnchor.constraint(equalTo: topView.centerYAnchor),
                      self.centerXAnchor.constraint(equalTo: topView.centerXAnchor),
                      self.widthAnchor.constraint(equalToConstant: CGFloat(size)),
                      self.heightAnchor.constraint(equalToConstant: CGFloat(size)),
                  ])
                  self.layer.cornerRadius = frame.height/3
                  backgroundColor = .secondarySystemBackground
                  self.layer.addSublayer(circleLayer)
                  calculateCirclePath()
                  animateCircle(duration: 1, repeats: true)
              }
          }
          
          func calculateCirclePath() {
              self.circlePath = UIBezierPath(arcCenter: CGPoint(x: size / 2, y: size / 2), radius: size / 2, startAngle: 0.0, endAngle: CGFloat(Double.pi*2), clockwise: true)
          }
          
          override func layoutSubviews() {
              circleLayer.frame = self.layer.bounds
          }
          
          private func animateCircle(duration: TimeInterval, repeats: Bool) {
              // Setup the CAShapeLayer with the path, colors, and line width
              circleLayer.path = circlePath.cgPath
              circleLayer.fillColor = UIColor.clear.cgColor
              circleLayer.strokeColor = UIColor.blue.cgColor
              circleLayer.lineWidth = 1.0
              
              // Don't draw the circle initially
              circleLayer.strokeEnd = 0.0
              
              // Add the circleLayer to the view's layer's sublayers
              self.layer.addSublayer(circleLayer)
              // We want to animate the strokeEnd property of the circleLayer
              let animation = CABasicAnimation(keyPath: "strokeEnd")
              animation.duration = duration
              animation.repeatCount = repeats ? .infinity : 1
              animation.fromValue = 0
              animation.toValue = 1
              animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut)
              circleLayer.strokeEnd = 0
              circleLayer.add(animation, forKey: "animateCircle")
              
              let rotationAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
              rotationAnimation.repeatCount = repeats ? .infinity : 1
              rotationAnimation.fromValue = 0.0
              rotationAnimation.toValue = Double.pi*3
              rotationAnimation.duration = duration
              rotationAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn)
              circleLayer.add(rotationAnimation, forKey: nil)
              
              let fadeAnimation = CABasicAnimation(keyPath: "opacity")
              fadeAnimation.repeatCount = repeats ? .infinity : 1
              fadeAnimation.fromValue = 1
              fadeAnimation.toValue = 0
              fadeAnimation.duration = duration
              fadeAnimation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn)
              circleLayer.add(fadeAnimation, forKey: nil)
          }
          
          func stopLoading() {
              self.removeFromSuperview()
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2020-09-22
        • 1970-01-01
        • 2011-12-11
        • 1970-01-01
        • 2010-10-22
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多