在 viewDidLoad() 中获取视图的渲染边界

Get rendered bounds of a view in viewDidLoad()

我整天都在寻求这方面的帮助,但找不到答案。

我有一个子视图,我正在其中绘制一个矩形,该矩形由子视图框起来,所以我需要知道自动布局调整的子视图的大小才能正确地框住它。我无法从 ViewDidLoad() 找到执行此操作的方法,以便在启动时正确呈现矩形。我尝试了以下方法:

  1. viewDidLoad() 中绘制矩形之前使用 dayView.setNeedsLayout() 后跟 dayView.layoutIfNeeded() 但是检查这些语句的任一侧显示 dayView.bounds 未更改。
  2. viewDidLayoutSubviews() 绘制视图,这有效,但导致我的矩形被绘制 5 次,因为每个重绘的子视图(我有 5 个)调用 viewDidLayoutSubviews()(包含矩形的相关子视图在 5 次调用中的第 4 次调用时重绘)——这似乎是在浪费资源,肯定有更好的方法吗?
  3. ViewDidLoad() 内绘制视图两次,希望第一次强制绘制会导致视图调整大小,以便第二次绘制可以访问第一次绘制后的新边界(我知道很绝望,但是它仍然不起作用)。

希望有人能帮忙。

func drawGradient(object: UIView, rect: CGRect, slackX: Int, gradWidth: Int, yPos: Int) -> Void {
    // the rectangle width and height set to fit within view with x & y border.

    let gradientView = UIView(frame: rect)
    let gradient = CAGradientLayer()

    gradient.frame = gradientView.frame
    gradient.colors = getDayGradientLocations().gradientCol
    gradient.locations = getDayGradientLocations().gradientLoc
    dayView.layer.addSublayer(gradient)

    let civilDawn = getTimeAsProportionOfDay(time: tides.civilDawn) * Double(rect.height) + Double(yPos)
    let path = UIBezierPath()
    path.move(to: CGPoint(x: slackX, y: Int(civilDawn)))
    path.addLine(to: CGPoint(x: slackX + Int(rect.width), y: Int(civilDawn)))

    let shapeLayer = CAShapeLayer()
    shapeLayer.path = path.cgPath
    shapeLayer.strokeColor = UIColor.red.cgColor
    shapeLayer.lineWidth = CGFloat(2)

    let civilDusk = getTimeAsProportionOfDay(time: tides.civilDusk) * Double(rect.height) + Double(yPos)
    path.move(to: CGPoint(x: slackX, y: Int(civilDusk)))
    path.addLine(to: CGPoint(x: slackX + Int(rect.width), y: Int(civilDusk)))
    shapeLayer.path = path.cgPath
    shapeLayer.strokeColor = UIColor.red.cgColor
    shapeLayer.lineWidth = CGFloat(2)

    object.layer.addSublayer(shapeLayer)

    drawLabel(object: object, rect: rect, slackX: slackX, offset: 15, time: tides.civilDawn)
    drawLabel(object: object, rect: rect, slackX: slackX, offset: -15, time: tides.civilDusk)
}

转到 viewDidLoad 中的主线程并执行操作将解决您的问题

         DispatchQueue.main.async { 
                // here you can add anything it will have proper frame
            }

一些观察:

  1. 如果您在视图控制器中调整视图的 frame,正确的位置是 viewDidLayoutSubviews。是的,这被调用了很多次,但它通常不会对性能产生任何可观察到的影响。

    我不会建议 setNeedsLayoutlayoutIfNeededviewDidLoad 中的任何那些极其脆弱的技术。如果您要在视图控制器中执行此操作,viewDidLayoutSubviews 是正确的位置。

  2. 通常,如果要自定义子视图绘制和子视图布局,您会在视图的 layoutSubviews 中执行此操作,而不是在任何视图控制器方法中执行此操作。

    同样,如果你正在做任何手动绘图,你会把它放在 UIView 子类(或任何相关的 CALayer 子类)中,而不是视图控制器。

  3. 更好的是,如果可以的话,最好让自动布局系统为您处理,而不是手动调整框架。如果您发现自己手动调整了 frame,通常会有更好的模式。

    FWIW,您可以根据其子视图的大小(或固有大小)定义容器视图的约束(并设置相关视图的内容拥抱和压缩阻力)。我们经常将自动布局视为自上而下的引擎,但它可以双向工作。

如果您向我们展示您的“绘图”代码 and/or 一两个屏幕快照,我们可能会提供更具体的建议。