【问题标题】:Why are these CAShapeLayers not going where expected?为什么这些 CAShapeLayers 没有达到预期的效果?
【发布时间】:2019-05-08 22:21:05
【问题描述】:

我正在开发自定义加载指示器,但遇到了很多关于 CAShapeLayers 的问题。

加载指示器将包含在自定义 UIView 中,以便任何 viewController 都可以使用它。

第一期:

子视图的框架与边界不匹配。

当使用此代码在框架的每个角落显示一个圆圈时,圆圈被放置在一个正方形中,但它不在视图附近。 导入 UIKit

视图控制器:

class MergingCicles: UIViewController, HolderViewDelegate {
func animateLabel() {

}

var holderView = HolderView(frame: CGRect.zero)

override func viewDidLoad() {
    super.viewDidLoad()
}

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    addHolderView()
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
}

func addHolderView() {
    let boxSize: CGFloat = 100.0
    holderView.frame = CGRect(x: view.bounds.width / 2 - boxSize / 2,
                              y: view.bounds.height / 2 - boxSize / 2,
                              width: boxSize,
                              height: boxSize)
    holderView.parentFrame = view.frame
    holderView.delegate = self
    holderView.center = self.view.center
    view.addSubview(holderView)
    holderView.addCircleLayer()
}
}

子视图:

Import UIKit

protocol HolderViewDelegate:class {
func animateLabel()
}

class HolderView: UIView {
let initalLayer = InitialLayer()
let triangleLayer = TriangleLayer()
let redRectangleLayer = RectangleLayer()
let blueRectangleLayer = RectangleLayer()
let arcLayer = ArcLayer()

var parentFrame :CGRect = CGRect.zero
weak var delegate:HolderViewDelegate?

override init(frame: CGRect) {
    super.init(frame: frame)
    backgroundColor = UIColor.clear
}

required init(coder: NSCoder) {
    super.init(coder: coder)!
}

func addCircleLayer() {
    var circleLocations = [CGPoint]()
    let offset = CircleLayer().maxSize / 2
    circleLocations.append(CGPoint(x: self.frame.maxX - offset, y: self.frame.maxY - offset))
    circleLocations.append(CGPoint(x: self.frame.minX + offset, y: self.frame.minY + offset))
    circleLocations.append(CGPoint(x: self.frame.maxX - offset, y: self.frame.minY + offset))
    circleLocations.append(CGPoint(x: self.frame.minX + offset, y: self.frame.maxY - offset))
    circleLocations.append(layer.anchorPoint)
    for point in circleLocations {
        let circle = CircleLayer()
        circle.updateLocation(Size: .medium, center: point)
            self.layer.addSublayer(circle)

    }
    self.backgroundColor = .blue
   // layer.anchorPoint = CGPoint(x: (self.bounds.maxX + self.bounds.maxX)/2, y: (self.bounds.maxY + self.bounds.minY)/2)
    let rotationAnimation: CABasicAnimation = CABasicAnimation(keyPath: "transform.rotation.z")
    rotationAnimation.toValue = CGFloat(Double.pi * 2)
    rotationAnimation.duration = 0.45
    rotationAnimation.isCumulative = true
    //rotationAnimation.repeatCount = 1000
    //rotationAnimation.isRemovedOnCompletion = true
  //  layer.add(rotationAnimation, forKey: nil)
}

}

圆形层:

import Foundation
import UIKit

enum ShapeSize {
    case medium
    case small
    case large
}
class CircleLayer: CAShapeLayer {
let animationDuration: CFTimeInterval = 0.3
let maxSize = CGFloat(50)
override init() {
    super.init()
    fillColor = UIColor.red.cgColor
}

func updateLocation(Size: ShapeSize, center: CGPoint){
    switch Size {
    case .medium:
        path = UIBezierPath(ovalIn: CGRect(x: center.x, y: center.y, width: maxSize/3, height: maxSize/3)).cgPath
    case .small:
        path = UIBezierPath(ovalIn: CGRect(x: center.x, y: center.y, width: (2*maxSize)/3, height: (2*maxSize)/3)).cgPath
    case .large:
        path = UIBezierPath(ovalIn: CGRect(x: center.x, y: center.y, width: maxSize, height: maxSize)).cgPath
    }
}

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

结果:

这确实表明框架不在 uiView 附近。

如果我将addCircleLayer 改为使用边界,我会得到更接近的结果:

但圆圈仍然不在角落里(除了右下角,那个是正确的)。似乎在视图的左侧和顶部有一些额外的空间没有使用 self.bounds 捕获。

最终目标也是围绕中心旋转圆圈 360 度,但如左上角的圆圈所示,图层锚点不在视图中心,我将锚点更改为中心圆圈,然后屏幕上什么也没有出现。

【问题讨论】:

  • 尝试在 viewdidlayoutsubviews 中调用 addHolderView() 而不是 viewdidappear 以确保您的视图边界符合您的预期。请记住,此方法将被多次调用,因此请确保您不要每次都重新添加图层
  • 好主意,但得到相同的结果。

标签: swift uiview uiviewanimation cashapelayer


【解决方案1】:

你说的是

circleLocations.append(CGPoint(x: self.frame.maxX - offset, y: self.frame.maxY - offset))

self.frame 是视图在其自己的父视图中所在的位置。因此,形状层最终会从视图偏移,就像视图从它自己的父视图偏移一样多。无论你在这里说frame,你的意思是bounds

【讨论】:

    【解决方案2】:

    我发现问题出在绘制圆圈时,我使用的是UIBezierPath(ovalIn:CGRect, width: CGFloat, height: CGFloat,它使用的是圆圈左侧的 x 值。当我更改为UIBezierPath(arcCenter: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat, clockwise: Bool) 时,该点被用作圆心,并在使用 self.bounds 计算点时使其完全符合预期。

    之后,我不再需要更改锚点,因为它默认位于正确的位置。

    我不明白为什么框架在一个完全不同的位置,但它不再影响项目。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-21
      • 1970-01-01
      • 1970-01-01
      • 2016-01-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多