如何以编程方式快速定位图层?

Posted

技术标签:

【中文标题】如何以编程方式快速定位图层?【英文标题】:How to position Layers in swift programmatically? 【发布时间】:2019-12-12 23:21:13 【问题描述】:

我正在尝试定位一个圆形进度条,但我经常失败。我想我不理解框架、视图和边界的概念。我发现这篇关于堆栈溢出的帖子准确地向我展示了如何构建一个圆形进度条。

但是,在帖子中,使用 CGRect(x: 100, y: 100, width: 100, height: 100) 创建了一个 circleView 作为 UIView

在我的情况下,手动设置 x 和 y 坐标是一个很大的问题。所以 circleView 必须在它的父视图的中心。

这是我的视图层次结构:

view -> view2ForHomeController -> middleView -> circleView

所以一切都使用自动布局定位。这是问题所在:circleView 正在正确添加,它将自身定位在我指定的 x 和 y 值,但我如何指定 middleView 中心的 x 和 y 值。我尝试了以下方法,但中心值返回为 0.0、0.0。

self.view.addSubview(self.view2ForHomeController)
self.view2ForHomeController.fillSuperview()

let xPosition = self.view2ForHomeController.middleView.frame.midX 
let yPostion = self.view2ForHomeController.middleView.frame.midY
print(xPosition) // ------- PRINTS ZERO
print(yPostion)  // ------- PRINTS ZERO

let circle = UIView(frame: CGRect(x: xPosition, y: yPostion, width: 100, height: 100))
circle.backgroundColor = UIColor.green
self.view2ForHomeController.middleView.addSubview(circle)

var progressCircle = CAShapeLayer()
progressCircle.frame = self.view.bounds

let lineWidth: CGFloat = 10
let rectFofOval = CGRect(x: lineWidth / 2, y: lineWidth / 2, width: circle.bounds.width - lineWidth, height: circle.bounds.height - lineWidth)

let circlePath = UIBezierPath(ovalIn: rectFofOval)

progressCircle = CAShapeLayer ()
progressCircle.path = circlePath.cgPath
progressCircle.strokeColor = UIColor.white.cgColor
progressCircle.fillColor = UIColor.clear.cgColor
progressCircle.lineWidth = 10.0
progressCircle.frame = self.view.bounds
progressCircle.lineCap = CAShapeLayerLineCap(rawValue: "round")

circle.layer.addSublayer(progressCircle)
circle.transform = circle.transform.rotated(by: CGFloat.pi/2)

let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = 0
animation.toValue = 1.1
animation.duration = 1
animation.repeatCount = MAXFLOAT
animation.fillMode = CAMediaTimingFillMode.forwards
animation.isRemovedOnCompletion = false
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn)

progressCircle.add(animation, forKey: nil)

【问题讨论】:

【参考方案1】:

Frame 是根据 superview/superlayer 坐标。如果你要说

circle.layer.addSublayer(progressCircle)

那么您必须根据circle.layerboundsprogressCircle 一个frame

至于居中,一般来说,将子层居中于其父层中:

theSublayer.position = CGPoint(
    x:theSuperlayer.bounds.midX, 
    y:theSuperlayer.bounds.midY)

为了让子视图在其父视图中居中,您说:

theSubview.center = CGPoint(
    x:theSuperview.bounds.midX, 
    y:theSuperview.bounds.midY)

【讨论】:

是的,如果您看到我所做的代码。问题是试图计算父视图的 x 和 y 坐标。我的代码的前 6 行会告诉你我卡在哪里了 不,这根本不是你所做的。你说的是progressCircle.frame = self.view.bounds。正如我在回答中所说的那样,这是完全错误的。 是的,更改没有任何效果。就像我说的,问题不在于构建层或视图。一切正常,当我手动指定 x 和 y 坐标时,我可以手动定位它。问题是我如何将它定位在其超级视图的中心。感谢您提出改变这一点的建议:) 好的,添加了有关如何居中的信息。【参考方案2】:

边界是图层/视图在其本地坐标系中的坐标。框架是图层/视图在其父坐标系中的坐标。由于图层不参与自动布局,您应该实现UIViewController.viewDidLayoutSubviews(或UIView.layoutSubLayers)并将图层的frame设置为其父图层视图的bounds(UIView的支持层本质上是该视图的 CoreGraphics 版本)。

这也意味着你需要在他们的布局方法中重新计算你的路径。如果这很昂贵,那么在单位空间中绘制路径并使用图层的变换将其放大到视图的尺寸。

【讨论】:

这是有用的信息,但是,我是一个菜鸟,即使阅读了大量的文档,我在涉及层时也会出错。如果您看到代码,我可以成功创建一个圆形视图并在其中放置一个圆形进度条。唯一的问题是如何将整个圆形视图包放置在中间视图的中心?如果我手动输入 x = 100 和 y = 100。它可以工作,但我想自动计算 middleView 的中心并将其放置在那里。尝试了 layoutsubviews 并没有工作。 Def在这里做错了什么。有答案吗? 为了更清楚,我首先添加 view2ForHomeController,然后添加 fillSuperView()。这个 view2ForHomeController 由一个名为 middleView 的子视图组成。我需要将 circleView 添加到这个 middleView 的中心 如果你简单地浏览了我发布的前 6 行代码,你就会明白我在哪里挣扎:) 您的代码没有包含足够的上下文供我确定,但您可能在 viewDidLoad 或 init 中执行此操作,并且您的框架为零,因为尚未发生自动布局;这就是为什么您需要在 viewDidLayoutSubviews 或 layoutSublayers 中计算位置和大小的原因。我这里有一个例子:github.com/joshuajhomann/RingProgressView/blob/master/… 谢谢乔希,是的,我也检查了这篇文章。没错,我是在 viewDidLoad 中做的。我也在 viewDidlayout 中尝试了同样的方法。我想我会继续寻找:)【参考方案3】:

解决方法是先添加子视图,然后在

处创建整个循环进度视图
override func viewDidLayoutSubviews()
     super.viewDidLayoutSubviews()
     // Add and position the circular progress bar and its layers here

【讨论】:

以上是关于如何以编程方式快速定位图层?的主要内容,如果未能解决你的问题,请参考以下文章

如何以面向协议的方式快速将图层添加到 UIButton 子类?

异步请求积压可视化|如何 1 分钟内快速定位函数计算积压问题

异步请求积压可视化|如何 1 分钟内快速定位函数计算积压问题

异步请求积压可视化|如何 1 分钟内快速定位函数计算积压问题

Emacs 是如何实现快速查找和定位代码的?

如何以编程方式添加标签并以编程方式使用自动布局定位它