代码之家  ›  专栏  ›  技术社区  ›  Kendall Hopkins

在UIView之间拖动UIView

  •  8
  • Kendall Hopkins  · 技术社区  · 15 年前

    我有一个包含在UIView对象a中的UIView对象X。我希望能够触摸X并将其从对象a中移除,然后将其移动到对象B(另一个UIView)。对象A和对象B都位于同一超级UIView中。

      A        B
    _____    _____
    |   |    |   |
    | X | -> |   |
    |___|    |___|
    

    这就是我目前所拥有的。

    @implementation X_UIView
    
    float deltaX;
    float deltaY;
    
    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
        [self.superview.superview addSubview:self]; //pop dragged view outside of container view
    
        CGPoint beginCenter = self.center;
    
        UITouch * touch = [touches anyObject];
        CGPoint touchPoint = [touch locationInView:self.superview];
    
        deltaX = touchPoint.x - beginCenter.x;
        deltaY = touchPoint.y - beginCenter.y;
    }
    
    - (void) touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
        UITouch * touch = [touches anyObject];
        CGPoint touchPoint = [touch locationInView:self.superview];
    
        // Set the correct center when touched 
        touchPoint.x -= deltaX;
        touchPoint.y -= deltaY;
    
        self.center = touchPoint;
    }
    
    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
        //discover view that event ended was over and add self as a subview.
    }
    
    @end
    
    2 回复  |  直到 15 年前
        1
  •  10
  •   Luke Hardik Soni    13 年前

    呼叫 [[touches anyObject] locationInView: self.superview] 在容器视图中获取手指下的点。然后发送 self.superview -hitTest:withEvent: 找出视图X在里面。请注意,它将始终返回X,因此必须重写其中一个 -pointIsInside:withEvent: -hitTest:withEvent: 在你拖拽的时候返回nil。这种混乱是我在容器视图而不是拖拽视图中实现这种跟踪的原因。

        2
  •  2
  •   Imanou Petit    6 年前


    视图容器.swift

    import MobileCoreServices
    import UIKit
    
    enum ViewContainerError: Error {
        case invalidType, unarchiveFailure
    }
    
    class ViewContainer: NSObject {
    
        let view: UIView
    
        required init(view: UIView) {
            self.view = view
        }
    
    }
    
    extension ViewContainer: NSItemProviderReading {
    
        static var readableTypeIdentifiersForItemProvider = [kUTTypeData as String]
    
        static func object(withItemProviderData data: Data, typeIdentifier: String) throws -> Self {
            if typeIdentifier == kUTTypeData as String {
                guard let view = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as? UIView else { throw ViewContainerError.unarchiveFailure }
                return self.init(view: view)
            } else {
                throw ViewContainerError.invalidType
            }
        }
    
    }
    
    extension ViewContainer: NSItemProviderWriting {
    
        static var writableTypeIdentifiersForItemProvider = [kUTTypeData as String]
    
        func loadData(withTypeIdentifier typeIdentifier: String, forItemProviderCompletionHandler completionHandler: @escaping (Data?, Error?) -> Void) -> Progress? {
            if typeIdentifier == kUTTypeData as String {
                do {
                    let data = try NSKeyedArchiver.archivedData(withRootObject: view, requiringSecureCoding: false)
                    completionHandler(data, nil)
                } catch {
                    completionHandler(nil, error)
                }
            } else {
                completionHandler(nil, ViewContainerError.invalidType)
            }
            return nil
        }
    
    }
    

    import UIKit
    
    class ViewController: UIViewController {
    
        let redView = UIView()
        let greenView = UIView()
    
        override func viewDidLoad() {
            super.viewDidLoad()
    
            let blueView = UIView()
            blueView.backgroundColor = .blue
    
            greenView.backgroundColor = .green
            greenView.isUserInteractionEnabled = true
            greenView.addSubview(blueView)
            setConstraintsInSuperView(forView: blueView)
    
            redView.backgroundColor = .red
            redView.isUserInteractionEnabled = true
    
            let greenViewDropInteraction = UIDropInteraction(delegate: self)
            let greenViewDragInteraction = UIDragInteraction(delegate: self)
            greenViewDragInteraction.isEnabled = true
            greenView.addInteraction(greenViewDragInteraction)
            greenView.addInteraction(greenViewDropInteraction)
    
            let redViewDropInteraction = UIDropInteraction(delegate: self)
            let redViewDragInteraction = UIDragInteraction(delegate: self)
            redViewDragInteraction.isEnabled = true
            redView.addInteraction(redViewDragInteraction)
            redView.addInteraction(redViewDropInteraction)
    
            let stackView = UIStackView(arrangedSubviews: [greenView, redView])
            view.addSubview(stackView)
            stackView.distribution = .fillEqually
            stackView.frame = view.bounds
            stackView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        }
    
    }
    
    extension ViewController {
    
        // MARK: Helper methods
    
        func setConstraintsInSuperView(forView subView: UIView) {
            subView.translatesAutoresizingMaskIntoConstraints = false
            NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "H:|-[subView]-|", options: [], metrics: nil, views: ["subView": subView]))
            NSLayoutConstraint.activate(NSLayoutConstraint.constraints(withVisualFormat: "V:|-[subView]-|", options: [], metrics: nil, views: ["subView": subView]))
        }
    
    }
    
    extension ViewController: UIDragInteractionDelegate {
    
        func dragInteraction(_ interaction: UIDragInteraction, itemsForBeginning session: UIDragSession) -> [UIDragItem] {
            guard let containedView = interaction.view?.subviews.first else { return [] }
            let viewContainer = ViewContainer(view: containedView)
            let itemProvider = NSItemProvider(object: viewContainer)
            let item = UIDragItem(itemProvider: itemProvider)
            item.localObject = viewContainer.view
            return [item]
        }
    
        func dragInteraction(_ interaction: UIDragInteraction, sessionWillBegin session: UIDragSession) {
            guard let containedView = interaction.view?.subviews.first else { return }
            containedView.removeFromSuperview()
        }
    
        func dragInteraction(_ interaction: UIDragInteraction, previewForLifting item: UIDragItem, session: UIDragSession) -> UITargetedDragPreview? {
            guard let containedView = interaction.view?.subviews.first else { return nil }
            return UITargetedDragPreview(view: containedView)
        }
    
        func dragInteraction(_ interaction: UIDragInteraction, item: UIDragItem, willAnimateCancelWith animator: UIDragAnimating) {
            animator.addCompletion { _ in
                guard let containedView = item.localObject as? UIView else { return }
                interaction.view!.addSubview(containedView)
                self.setConstraintsInSuperView(forView: containedView)
            }
        }
    
        func dragInteraction(_ interaction: UIDragInteraction, prefersFullSizePreviewsFor session: UIDragSession) -> Bool {
            return true
        }
    
    }
    
    extension ViewController: UIDropInteractionDelegate {
    
        func dropInteraction(_ interaction: UIDropInteraction, canHandle session: UIDropSession) -> Bool {
            return session.canLoadObjects(ofClass: ViewContainer.self) && session.items.count == 1
        }
    
        func dropInteraction(_ interaction: UIDropInteraction, sessionDidUpdate session: UIDropSession) -> UIDropProposal {
            let dropLocation = session.location(in: view)
            let operation: UIDropOperation
            if interaction.view!.frame.contains(dropLocation) && session.localDragSession != nil {
                operation = .move
            } else {
                operation = .cancel
            }
            return UIDropProposal(operation: operation)
        }
    
        func dropInteraction(_ interaction: UIDropInteraction, performDrop session: UIDropSession) {
            session.loadObjects(ofClass: ViewContainer.self) { viewContainers in
                guard let viewContainers = viewContainers as? [ViewContainer], let viewContainer = viewContainers.first else { return }
                interaction.view!.addSubview(viewContainer.view)
                self.setConstraintsInSuperView(forView: viewContainer.view)
            }
        }
    
    }
    

    enter image description here

    推荐文章