2010-10-01 72 views
8

我有一個包含在UIView對象A中的UIView對象X.我希望能夠觸摸X並將其從對象A中移除並將其移入對象B(另一個UIView)中。兩個對象A & B都在同一個超級UIView中。在UIViews之間拖動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 
+0

你有沒有完成這個?我試圖做的完全一樣,但是當我將X添加到最頂層的父項時,就像觸摸開始它會消失一樣。因此,當我拖動它時,我無法看到視圖。非常感謝您的幫助。 – 2013-02-07 14:27:49

回答

10

撥打[[touches anyObject] locationInView: self.superview]在容器視圖中獲取手指下的點。然後發送self.superview -hitTest:withEvent:來查看X在裏面的視圖。請注意,它將始終返回X,因此在拖動時必須覆蓋-pointIsInside:withEvent:-hitTest:withEvent:以返回零。這種kludge是我在容器視圖中實現這種跟蹤的原因,而不是在拖動視圖中。

+0

您將如何在容器視圖中實現跟蹤? – 2010-10-01 20:11:13

+1

第二個想法是,完全有效的理由在X中進行所有跟蹤,所以不要介意。順便說一下,在追蹤時,您可以測試X和B幀的相交而不是檢查手指的位置。根據您的需求,視覺反饋可能會更好。 – Costique 2010-10-02 06:01:26

0

使用iOS 11,您可以使用拖放式API來解決您的問題。以下Swift 4代碼顯示瞭如何執行。


ViewContainer.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 = NSKeyedUnarchiver.unarchiveObject(with: 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 { 
      let data = NSKeyedArchiver.archivedData(withRootObject: view) 
      completionHandler(data, nil) 
     } else { 
      completionHandler(nil, ViewContainerError.invalidType) 
     } 
     return nil 
    } 

} 

ViewController.swift

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 
     redView.addInteraction(greenViewDragInteraction) 
     greenView.addInteraction(greenViewDropInteraction) 

     let redViewDropInteraction = UIDropInteraction(delegate: self) 
     let redViewDragInteraction = UIDragInteraction(delegate: self) 
     redViewDragInteraction.isEnabled = true 
     greenView.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