想法
您知道容器 UIView 的宽度和高度。而且,每张卡片的宽度和高度都相同。我会通过计算网格来解决这个问题。
即使您想随机显示卡片,依赖网格也会为您提供标准化的中心数组,您可以使用这些数组来生成随机外观(将卡片放置在属于网格一部分的任意随机中心,例如)。
如果您要将卡片放置在真正的随机位置,您可能只想使用CGRectIntersectsRect(card1.frame, card2.frame) 来检测碰撞。
模式
首先,让我们将卡片的宽度和高度存储为常量。
let cardWidth = card.bounds.size.width
let cardHeight = card.bounds.size.height
作为概念的基本证明,假设您的容器视图宽度为 250 磅。假设卡片宽度为 5 点。这意味着您可以在一行中放置 250 / 5 = 50 张卡片,其中一排的高度相当于一张卡片。
一行中的中心数=该行中的卡片数。每个中心之间的距离相同。在下图中(如果我什至可以这样称呼它),[ 和 ] 代表一行的边缘。 -|- 代表一张卡片,其中| 是卡片的中心。
[ - | - - | - - | - - | - - | - ]
请注意每个中心距离下一个中心的距离如何。唯一需要考虑的是,边缘旁边的中心距离边缘只有一小段距离。就卡片而言,每个中心与下一个中心相距一整张牌,边缘旁边的中心与边缘相距半张牌。
模式的关键
此模式意味着特定行中任何卡片中心的 x 位置 = (cardWidth / 2) + (the card index * cardWidth)。事实上,这个伪方程也适用于 y 位置。
代码
这里有一些使用这种方法创建中心数组的 Swift。
var centers = [CGPoint]()
let numberOfRows: CGFloat = containerView.bounds.size.height / cardHeight
let numberOfCardsPerRow: CGFloat = containerView.bounds.size.width / cardWidth
for row in 0 ..< Int(numberOfRows) {
for card in 0 ..< Int(numberOfCardsPerRow) {
// The row we are on affects the y values of all the centers
let yBasedOnRow = (cardHeight / 2) + (CGFloat(row) * cardHeight)
// The xBasedOnCard formula is effectively the same as the yBasedOnRow one
let xBasedOnCard = (cardWidth / 2) + (CGFloat(card) * cardWidth)
// Each possible center for this row gets appended to the centers array
centers.append(CGPoint(x: xBasedOnCard, y: yBasedOnRow))
}
}
此代码应为您的卡片创建一个中心网格。您可以围绕它构建一个函数,该函数返回一个随机中心用于放置卡片并跟踪使用的中心。
可能的改进
首先,我认为centers 数组可以做成一个矩阵([[CGPoint]]()),以便对点进行更多的逻辑存储。
其次,这段代码目前假设容器视图的宽度和高度可以被卡片的宽度和高度整除。例如,容器宽度为 177,卡片宽度为 5 会导致一些问题。可以通过多种不同的方式修复代码以解决此问题。