【问题标题】:How to get center point (CGPoint) of a UIView that has been set using autolayout如何获取已使用自动布局设置的 UIView 的中心点(CGPoint)
【发布时间】:2020-05-21 06:10:57
【问题描述】:

所以我还没有看到任何其他关于此的 SO 问题。基本上,我以编程方式设置了一个带有自动布局的 UIView。

当我尝试创建 UIBezierPath 时出现问题:

let circularPath = UIBezierPath(arcCenter: myView.center, radius: (91*(1.2))/2 - (8/2), startAngle: -CGFloat.pi / 2, endAngle: 2 * CGFloat.pi, clockwise: true)

问题是 myView.center 打印出:0.0, 0.0,因为我没有为 myView 设置 CGRect .frame,而是使用了自动布局(如下所示):

NSLayoutConstraint.activate([
    myView.heightAnchor.constraint(equalToConstant: 91),
    myView.widthAnchor.constraint(equalToConstant: 91),
    myView.centerXAnchor.constraint(equalToSystemSpacingAfter: myButton.centerXAnchor, multiplier: 1),
    myView.centerYAnchor.constraint(equalToSystemSpacingBelow: myButton.centerYAnchor, multiplier: 1),
])

也许我应该注意到 myView 是作为 myButton 的子视图添加的(尽管这并不重要..)

那么我该如何做呢?我怎样才能让 .center(一种 CGPoint 类型)在 UIBezierPath 中使用?谢谢!

【问题讨论】:

    标签: ios swift xcode autolayout uibezierpath


    【解决方案1】:

    一些观察:

    1. center 属性是当前视图的中心在父视图的坐标系中的位置。这可能不是您想要的。您需要CGPoint(x: myView.bounds.midX, y: myView.bounds.midY),它是current 视图的中点。

    2. 因为您正在使用约束,所以您需要将路径的创建推迟到应用约束之后,因为那是设置视图的 bounds 的时间。典型的解决方案是实现UIButton 子类,在该子类中您可以实现layoutSubviews,并在那里设置路径。

    例如,一个简单的圆形按钮可能定义如下:

    @IBDesignable
    class CircleButton: UIButton {
        let normalColor: UIColor = .red
        let highlightedColor: UIColor = .init(red: 0.5, green: 0, blue: 0, alpha: 1)
    
        lazy var shapeLayer: CAShapeLayer = {
            let shapeLayer = CAShapeLayer()
            shapeLayer.fillColor = normalColor.cgColor
            return shapeLayer
        }()
    
        override init(frame: CGRect = .zero) {
            super.init(frame: frame)
            configure()
        }
    
        required init?(coder: NSCoder) {
            super.init(coder: coder)
            configure()
        }
    
        func configure() {
            layer.addSublayer(shapeLayer)
        }
    
        override func layoutSubviews() {
            super.layoutSubviews()
    
            let center = CGPoint(x: bounds.midX, y: bounds.midY)
            let radius = min(bounds.height, bounds.width) / 2
            shapeLayer.path = UIBezierPath(arcCenter: center, radius: radius, startAngle: 0, endAngle: 2 * .pi, clockwise: true).cgPath
        }
    
        override var isHighlighted: Bool {
            didSet {
                if isHighlighted {
                    shapeLayer.fillColor = highlightedColor.cgColor
                } else {
                    shapeLayer.fillColor = normalColor.cgColor
                }
            }
        }
    }
    

    这种方法的优点是:

    • 您的视图控制器没有大量用于渲染圆圈的代码。

    • 无论渲染的大小如何,这都会起作用(如果您的约束不是针对固定大小,但可能会响应设备的方向、大小类等,这可能很有用)。

    • 如果您愿意,因为这是@IBDesignable,您可以在情节提要/NIB 中呈现它。

    【讨论】:

    • 我明白了。我想我应该给你更多信息:我当然在做 myView.center 之前设置了 myView 自动布局。哦,好的,作为对2.)的回应,是不是不可能做一些像myView.center这样简单的事情来获得一个自动布局视图的CGPoint?
    • @GEOG - 从理论上讲,如果您在设置约束后调用了layoutIfNeeded,那么应该设置bounds,然后bounds.midX 和bounds.midY 应该返回正确的值。但它有点脆弱,对尺寸变化没有反应(例如,如果你的圆形视图的约束与屏幕上的其他东西成比例,而不是固定的宽度和高度。但是有很多方法可以完成你想要的。我d 个人会把它放在一个按钮子类中,回复layoutSubviews,你就有了一个很好的、灵活的、通用的解决方案。
    • 是的,是我没有执行 myView.layoutIfNeeded()。它现在起作用了!也感谢你的课堂方法!
    【解决方案2】:

    您可以尝试使用边界而不是框架。它们可能会帮助您提供 UIVIew 的中心坐标。 center 属性是当前视图的中心在父视图坐标系中的位置。您可以尝试使用以下代码,它是当前视图的中点。

    CGPoint(x: myView.bounds.midX, y: myView.bounds.midY),
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多