我正在使用 UIKit 和 SpriteKit 在 Swift 中开发游戏原型(prototype)。库存(在此屏幕截图的底部)是一个 UIView
,其中包含各个项目的 UIImageView
subview 。在此示例中,是一个橡子。
我让橡子识别“平移”手势,这样我就可以拖动它。但是,它将其呈现在层次结构中其他 View 的下方。我希望它从库存中弹出并位于所有内容之上(甚至位于其父 View 之上),这样我就可以将其放到游戏中其他位置的其他 View 上。
这就是我在橡 subview 上的 panHandler
:
@objc func panHandler(gesture: UIPanGestureRecognizer){
switch (gesture.state) {
case .began:
removeFromSuperview()
controller.view.addSubview(self)
case .changed:
let translation = gesture.translation(in: controller.view)
if let v = gesture.view {
v.center = CGPoint(x: v.center.x + translation.x, y: v.center.y + translation.y)
}
gesture.setTranslation(CGPoint.zero, in: controller.view)
default:
return
}
}
问题出在 .began
情况下,当我将其从 super View 中删除时,平移手势立即取消。是否可以从 super View 中删除 View 并将其添加为其他地方的 subview ,同时保持平移手势?
或者,如果我的方法完全错误,您能否指导我如何用另一种方法实现我的目标?
最佳答案
小答案是,如果您不在 View 上调用 removeFromSuperview()
并将其作为 subview 立即添加到 Controller View 中,则可以保持手势正常工作,但这是不对的这样做的方法是因为如果用户取消拖动,您将不得不再次重新添加到您的主视图,并且如果该 View 您的拖动很重,不知何故它会很快变得迟缓和困惑
长答案,在我看来这是正确的方法,苹果在所有拖放 API 中实际所做的是
您实际上可以制作要拖动的 View 的快照,并将其添加为保存所有 View 的 Controller View 的 subview ,然后调用 bringSubviewToFront(_ view: UIView)
来制作确保它是层次结构中最顶层的 View ,并传入您为拖动 View 拍摄的快照
在.began
中您可以隐藏原始 View ,在.ending
中您可以再次显示它
并且在 .ending
上,您可以拍摄该快照并将其添加到放置 View 中,或者对其放置坐标执行任何其他操作
我做了一个示例项目来应用它 这是 Storyboard设计和 View 层次结构
这是ViewController代码
class ViewController: UIViewController {
@IBOutlet var topView: UIView!
@IBOutlet var bottomView: UIView!
@IBOutlet var smallView: UIView!
var snapshotView: UIView?
override func viewDidLoad() {
super.viewDidLoad()
let pan = UIPanGestureRecognizer(target: self, action: #selector(panning(_:)))
smallView.addGestureRecognizer(pan)
}
@objc private func panning(_ pan: UIPanGestureRecognizer) {
switch pan.state {
case .began:
smallView.backgroundColor = .systemYellow
snapshotView = smallView.snapshotView(afterScreenUpdates: true)
smallView.backgroundColor = .white
if let snapshotView = self.snapshotView {
self.snapshotView = snapshotView
view.addSubview(snapshotView)
view.bringSubviewToFront(snapshotView)
snapshotView.backgroundColor = .blue
snapshotView.center = bottomView.convert(smallView.center, to: view)
}
case .changed:
guard let snapshotView = snapshotView else {
fallthrough
}
smallView.alpha = 0
let translation = pan.translation(in: view)
snapshotView.center = CGPoint(x: snapshotView.center.x + translation.x, y: snapshotView.center.y + translation.y)
pan.setTranslation(.zero, in: view)
case .ended:
if let snapshotView = snapshotView {
let frame = view.convert(snapshotView.frame, to: topView)
if topView.frame.contains(frame) {
topView.addSubview(snapshotView)
snapshotView.frame = frame
smallView.alpha = 1
} else {
bottomView.addSubview(snapshotView)
let newFrame = view.convert(snapshotView.frame, to: bottomView)
snapshotView.frame = newFrame
UIView.animate(withDuration: 0.33, delay: 0, options: [.curveEaseInOut]) {
snapshotView.frame = self.smallView.frame
} completion: { _ in
self.snapshotView?.removeFromSuperview()
self.snapshotView = nil
self.smallView.alpha = 1
}
}
}
default: break
}
}
}
结果是这样的
关于ios - 如何在平移时将 UIView 移动到另一个父级?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69731652/