iOS Swift 4个画面游戏滑动框

iOS Swift 4 Screen game swipe boxes

我正在创建一个应用程序,以便用户必须从屏幕上滑动所有框。目标是滑动所有框,直到所有框都被滑动,如下例所示。

所以我的问题是:

  1. 是使用 Stack View 创建框更好还是通过屏幕上的坐标手动绘制更好?
  2. 如何检测用户是否滑动了框(使用 UIGestureRecognizer)?

注意:当用户滑动框时,滑动的框会变成其他颜色。

堆栈视图或手动都应该能很好地工作。在这种情况下,我会选择手动操作,但这只是一种偏好,因为您可能拥有更多控制权。但是有一个缺点是当屏幕尺寸改变时你需要重新定位它们。第三个选项也是集合视图。

手势识别器应该非常简单。您只需将它添加到这些单元格的超级视图中,并在它移动或开始时检查位置。平移手势似乎是最合适的,但它不会检测用户是否只是点击屏幕。这可能是一项功能,但如果你想处理所有触摸,你应该使用零按压持续时间的长按手势(这没什么意义,我知道但它有效),或者你可以简单地覆盖触摸方法:

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first {
        handleDrag(at: touch.location(in: viewWhereAllMiniViewsAre))
    }
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
    if let touch = touches.first {
        handleDrag(at: touch.location(in: viewWhereAllMiniViewsAre))
    }
}

func handleDrag(at location: CGPoint) {
    // TODO: handle the nodes
}

手势识别程序会做类似的事情:

func onDrag(_ sender: UIGestureRecognizer) {
    switch sender.state {
    case .began, .changed, .ended, .cancelled: handleDrag(at: sender.location(in: viewWhereAllMiniViewsAre))
    case .possible, .failed: break
    }
}

现在您所需要的只是数据源。所有项目的数组应该足够了。喜欢:

static let rows: Int = 10
static let columns: Int =  10

var nodes: [Node] = {
    return Array<Node>(repeating: Node(), count: LoginViewController.rows * LoginViewController.columns)
}()

以及您的所有迷你视图的列表:

var nodeViews: [UIView] = { ... position them or get them from stack view or from collection view }

现在触摸手柄上的实现:

func handleDrag(at location: CGPoint) {
    nodeViews.enumerated().forEach { index, view in
        if view.frame.contains(location) {
            view.backgroundColor = UIColor.green
            nodes[index].selected = true
        }
    }
}

这只是一个例子。至少从维护的角度来看,这是一个简单的而不是一个糟糕的。一般来说,我宁愿有一个自定义 UIView 子类的节点视图,并引用一个节点。它还应该使用委托挂钩到 Node 实例,以便节点在选择状态更改时报告。

这样你在处理触摸时就有了更简洁的解决方案:

func handleDrag(at location: CGPoint) {
    nodeViews.first(where: { [=15=].frame.contains(location) }).node.selected = true
}

然后检查是否全部为绿色

var allGreen: Bool {
    return !nodes.contains(where: { [=16=].selected == false })
}