【问题标题】:Determining if UIView in array of UIView's overlap with each other at all, and then adjust position确定 UIView 数组中的 UIView 是否完全相互重叠,然后调整位置
【发布时间】:2021-01-16 13:59:56
【问题描述】:

我在下面有一个循环,它应该检测UIView 数组中的视图是否完全相互重叠。如果是,则调整其center 值。

每个视图都是 25x25。

func drawCircles() {
        for i in 0..<circles.count{
            circles[i].center = getRandomPoint()
            for j in 0..<circles.count{
                if(i != j) {
                    let comparingCentre = circles[j].center
                    let dist = distance(comparingCentre, circles[i].center)
                    if dist <= 25 {
                        
                        var newCenter = circles[i].center
                        var centersVector = CGVector(dx: newCenter.x - comparingCentre.x, dy: newCenter.y - comparingCentre.y)
                     
                        //Circle width is 25
                        centersVector.dx *= 26 / dist
                        centersVector.dy *= 26 / dist
                        newCenter.x = comparingCentre.x + centersVector.dx
                        newCenter.y = comparingCentre.y + centersVector.dy
                        circles[i].center = newCenter
                    }
                }
            }
        }
...
}

以下是生成随机CGPoint 的方法,该CGPoint 设置为视图的中心:

func getRandomPoint() -> CGPoint {
    let viewMidX = self.circlesView.bounds.midX
    let viewMidY = self.circlesView.bounds.midY
    
    let xPosition = self.circlesView.frame.midX - viewMidX + CGFloat(arc4random_uniform(UInt32(viewMidX*2)))
    let yPosition = self.circlesView.frame.midY - viewMidY + CGFloat(arc4random_uniform(UInt32(viewMidY*2)))
    let point = CGPoint(x: xPosition, y: yPosition)
    return point
}

下面是确定两个UIView之间距离的方法。

func distance(_ a: CGPoint, _ b: CGPoint) -> CGFloat {
    let xDist = a.x - b.x
    let yDist = a.y - b.y
    return CGFloat(hypot(xDist, yDist))
}

但是,我仍然偶尔会遇到两个视图相互重叠的情况(请参阅下面的红圈部分):

编辑这是将圆圈添加到视图的代码:

func generateCircles() {
    numberOfCircles = Int.random(in: 1..<50)
    let circleWidth = CGFloat(25)
    let circleHeight = circleWidth
    
    var i = 0
    while i < numberOfCircles {
        let circleView = CircleView(frame: CGRect(x: 0.0, y: 0.0, width: circleWidth, height: circleHeight))
        let number = Int.random(in: 0..<2)
        if number == 1 {
            circleView.mainColor = .yellow
        } else {
            circleView.mainColor = .blue
        }
      
        circles.append(circleView)
        i += 1
    }
    drawCircles()
}

【问题讨论】:

  • 我预计您仍然会出现重叠,因为您只是将 两个 视图分开。如果没有我尝试运行您的代码,如果您的随机定位以 v1v2v3 结尾会发生什么情况:i.stack.imgur.com/fb1k0.png?您的代码是否要处理将v3v1 移开,只是让它与v2 重叠?然后,可能,将v3v2 移开......再次将其重新与v1 重叠?
  • @DonMag 我认为这是有道理的/描述了正在发生的事情
  • 为什么不改变你的 getRandomPoint() 的逻辑,让它只返回一个有效的随机点,然后你就不用担心移动圆圈了。
  • @valosip 好吧,理论上屏幕上的任何点都是有效的;这只是确定重叠的问题(或者我可能没有关注你?)
  • @narner 您在视图中添加圈子的方式和位置?

标签: ios swift uiview cgpoint


【解决方案1】:

根据我上面关于将比较距离的逻辑移动到随机点的创建中的评论,这是一个快速选项: 这可以清理,但我不想完全重写它并尽可能多地使用您的代码。

generateCirles 函数中,我只更改了您初始化 CircleView 的方式

func generateCircles() {
    numberOfCircles = Int.random(in: 1..<50)
    
    let circleWidth = CGFloat(25)
    let circleHeight = circleWidth
    
    for _ in 0..<numberOfCircles {
        let circleView = CircleView(frame: CGRect(origin: getRandomPoint(), size: (CGSize(width: circleWidth, height: circleHeight))))
        let number = Int.random(in: 0..<2)
        if number == 1 {
            circleView.mainColor = .yellow
        } else {
            circleView.mainColor = .blue
        }
        
        circles.append(circleView)
    }
    drawCircles()
}

getRandomPoint 中,我添加了一项检查,根据您现有的距离逻辑查看新点是否为有效点:

func getRandomPoint() -> CGPoint {
    let viewMidX = self.circlesView.bounds.midX
    let viewMidY = self.circlesView.bounds.midY
    
    let xPosition = self.circlesView.frame.midX - viewMidX + CGFloat(arc4random_uniform(UInt32(viewMidX*2)))
    let yPosition = self.circlesView.frame.midY - viewMidY + CGFloat(arc4random_uniform(UInt32(viewMidY*2)))
    let point = CGPoint(x: xPosition, y: yPosition)
    
    if !validatePoint(point) {
        return getRandomPoint()
    }
    return point
}

func validatePoint(_ point: CGPoint) -> Bool {
    for circle in circles {
        if distance(circle.frame.origin, point) <= 25 {
            return false
        }
    }
    return true
}

我从您发布的drawCircles 中删除了您的所有代码。

这是 300 个圆圈的样子:(我将视图框架用作 circlesView 框架,这就是圆圈与屏幕边界重叠的原因)这对您来说应该不是问题,因为我假设您的circlesView 框架设置为更小。

【讨论】:

    【解决方案2】:

    我认为你应该能够做这样的事情:

    let firstCircle = circles[i]
    let secondCircle = circles[j]
    let intersect = firstCircle.frame.intersection(secondCircle.frame)
    
    if intersect.isNull {
      // The circles do NOT overlap.
    } else {
      // The circles overlap. Handle accordingly.
    }
    

    请注意,这不能处理各种边缘情况,例如将相同的圆圈相互比较,但这应该可以简化它们是否重叠的理解。

    【讨论】:

    • 是的,非常接近;我在else 部分,我只是将circles[i] 的中心重置为一个新的随机点;但后来我处于这样一种情况,那个点可能与circles[j] 相交,所以不知道如何处理..
    猜你喜欢
    • 1970-01-01
    • 2012-06-17
    • 1970-01-01
    • 2010-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-10
    • 1970-01-01
    相关资源
    最近更新 更多