ios - 如何在平移时将 UIView 移动到另一个父级?

标签 ios swift uikit

我正在使用 UIKit 和 SpriteKit 在 Swift 中开发游戏原型(prototype)。库存(在此屏幕截图的底部)是一个 UIView,其中包含各个项目的 UIImageView subview 。在此示例中,是一个橡子。

Game View

我让橡子识别“平移”手势,这样我就可以拖动它。但是,它将其呈现在层次结构中其他 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
        }
    }
}

结果是这样的

enter image description here

关于ios - 如何在平移时将 UIView 移动到另一个父级?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69731652/

相关文章:

ios - UIButton 添加到 subview 后作为 UIView 返回?

ios - 蓝牙 4.0 低功耗和 iOS : How do I detect if device is bondable or not?

swift - 尝试更改 NSTextField 的值时得到 "Unexpectedly found nil while implicitly unwrapping an Optional value"

ios - 构建时间段的数据模型

ios - 是否可以为 MKMapView 上的用户定位 Pin 设置固定的屏幕位置?

swift - UIView 中神秘的 UIColor 行为以及 Swift 中的一般情况

ios - 运动开始 :withEvent: not called in AppDelegate in iOS 10

iphone - 在 iPhone 上使用 OpenGL 置换贴图

ios - 关于适用于 iOS 的 Google Maps SDK

swift - 如何对更新的变量使用相同的值,直到它们采用新值(Swift)