如何确定 UIBezierPath 相对于其父视图的 arcCenter?

Posted

技术标签:

【中文标题】如何确定 UIBezierPath 相对于其父视图的 arcCenter?【英文标题】:How do I determine the arcCenter for a UIBezierPath relative to its parent view? 【发布时间】:2021-11-17 05:42:32 【问题描述】:

我正在使用带有 UIBezierPath 的 CAShapeLayer 来制作圆形进度条。该代码需要基于 CGPoint 的 center 值。

let circleLayer = CAShapeLayer()
let circlePath = UIBezierPath(arcCenter: center, radius: 100, startAngle: -CGFloat.pi / 2, endAngle: 2 * CGFloat.pi, clockwise: true)

我已手动设置值如下:

let center = CGPoint(x: 70, y: 70)

但是这些值是相对于 superView 的,我需要使其相对于它的父 UIView。

UIView 中的所有其他元素都使用这样的编程 UI 代码进行约束:

sampleText.translatesAutoresizingMaskIntoConstraints = false
sampleText.topAnchor.constraint(equalTo: directionsTitle.bottomAnchor, constant: 0).isActive = true
sampleText.leadingAnchor.constraint(equalTo: timerFooter.leadingAnchor, constant: 8).isActive = true
sampleText.trailingAnchor.constraint(equalTo: timerFooter.trailingAnchor, constant: -8).isActive = true

固定值可能在一台设备上正常工作,但在更大或更小的设备上会不对齐。我的问题是,如何确定 UIView 的 center 的值将满足 CGPoint 所需的值?

我试过这个:

let centerX = view.centerXAnchor
let centerY = view.centerYAnchor
        
let center = CGPoint(x: centerX, y: centerY)

但是,这会引发错误:对初始化程序的调用中没有完全匹配

下图反映了形状放置的相对位置。蓝色框表示我想要放置圆圈的所需 UIView 区域。

非常感谢有智慧人士的建议。

【问题讨论】:

我不是 100% 关注您的描述。当您说 superView 和父 UIView 时...它们不是一回事吗?用这么小的 sn-ps 代码很难理解。我可以澄清一下...您是否有一个名为CircularProgressView 的 UIView?在那里你定义CAShapeLayer?然后您想将CircularProgressView 放在另一个视图中(称为OuterView)?但是您希望CAShapeLayer 的中心与OuterView 的中心对齐?请您显示更多代码或一些屏幕截图或其他内容吗?谢谢 抱歉混淆了。我添加了一个屏幕截图,显示了圆圈的所需放置区域。蓝色框是情节提要中的 UIView。 CGPoint 是相对于整个视图的,我需要弄清楚如何相对于 UIView 放置它。 不用担心。我想我解决了你的问题,我建议不要像这样使用 CAShapeLayers,而是创建你自己的自定义 UIView 包含 CAShapeLayer 并使用该视图来定位它。这是使用 CALayers 的标准方式。我已经为你写了一个简短的答案。 【参考方案1】:

啊,好吧,我想我明白你面临的问题是什么了。

我认为您的问题是您尝试使用 CAShapeLayer,就像它是 UIView 一样。而实际上他们根本不会那样做。

您应该做的是创建一个 UIView 子类并将CAShapeLayer 放在那里。现在您只需要担心CAShapeLayer 如何适合它自己的 UIView 子类。

要将图层“定位”到其他视图中,您实际上根本不需要担心这一点。您只需放置新的 UIView 子类,图层就会随之而来。

例如

class MyProgressView: UIView 
  let circleLayer: CAShapeLayer

  // add the circleLayer
  // add properties for customising the circle layer
  // Position the circle layer in the centre of the MyProgressView frame
  // I'd suggest using `layoutSubviews` or something for this.
  // etc...

现在...要定位您实际上不需要的“CircleLayer”。您只需将 MyProgressView 定位在您想要的位置,图层就是其中的一部分,因此可以继续使用。

从您的屏幕截图看来,您希望带有蓝色矩形的视图包含 circleLayer。如果是这种情况,那么让蓝色矩形查看您的自定义 UIView 子类并......完成。它现在将包含圆形视图。

RayWenderlich 有一些关于使用 CALayer 自定义视图的好东西...https://www.raywenderlich.com/10317653-calayer-tutorial-for-ios-getting-started#toc-anchor-002

【讨论】:

我曾考虑过这样的事情,但这解决了问题。谢谢。【参考方案2】:

听起来你想要 UIView 的 bounds 的中点,我认为是 yourView.bounds.midXyourView.bounds.midY

视图的bounds 是它自己的坐标空间。视图的frame 是它在其父空间中的位置。

UIView 有类似convertPoint:toCoordinateSpace: 和朋友的方法,用于在这些空间之间转换点和矩形。

【讨论】:

以上是关于如何确定 UIBezierPath 相对于其父视图的 arcCenter?的主要内容,如果未能解决你的问题,请参考以下文章

获取对话框中视图相对于其父级的位置

获取相对于其父级的对话框中的视图位置

如何相对于其父组件定位 React 组件?

如何使子高度相对于其父高度-Css

如何在 React Native 中获取 TextInput 相对于其父级或屏幕的光标位置

如何在 Swift 中未知宽度和高度的视图中居中 UIBezierPath 椭圆?