如何拖动 UIView 元素并更改位置?

Posted

技术标签:

【中文标题】如何拖动 UIView 元素并更改位置?【英文标题】:How do I drag UIView elements and change position? 【发布时间】:2017-08-25 08:54:39 【问题描述】:

我正在开发一个允许用户创建表单的 ios 应用程序。表单有许多 UIView 元素存储在堆栈中的 UIScrollView 中。就编辑而言,UIViews 应该改变顺序。

我如何实现这一目标?我想拖动任何 UIView 组件并将其移动到表单中的任何位置。例如。持有第三个元素将激活自身移动。将它移动到第二个元素上将替换它的位置。我正在使用平移手势来移动 UIView。现在我怎么知道点击的视图是否到达了任何 UIView 的顶部?

【问题讨论】:

github.com/bvogelzang/BVReorderTableView 用于重新排序 UITableview 的单元格 【参考方案1】:

据我了解您的要求,您希望用户能够移动/重新定位某些 UIView,例如在父视图中拖放。

我建议您使用启用了交互式移动的collectionView。如果你想使用一些库,那么你可以试试https://github.com/ra1028/RAReorderableLayout

或者对于UIView 拖放实现,您可以检查这个 https://blog.apoorvmote.com/uipangesturerecognizer-to-make-draggable-uiview-in-ios-swift/

【讨论】:

这应该是评论,而不是答案。 我现在不能使用collectionView,因为我已经写了很多代码来处理表单编辑。我现在只需要重新排列在 UIScrollView 中添加的 UIView。 @iPeter 正确!!但是没有权限添加评论:) @HirenPrajapati 看看blog.apoorvmote.com/…【参考方案2】:

UICollectionViewController 有几个简单的选项可以通过 canMoveItemAt 委托方法轻松处理 如果您有视图控制器,您可以尝试以下方式:

import UIKit

class LoveProfileEditViewViewController: BaseViewController 
    fileprivate var longPressGesture:UILongPressGestureRecognizer!
    @IBOutlet var theCollectionView:UICollectionView!
    public var items:[String]!

    override func viewDidLoad() 
        super.viewDidLoad()
        let horizontalLayout = UICollectionViewFlowLayout()
        horizontalLayout.scrollDirection = .horizontal
        self.theCollectionView.collectionViewLayout = horizontalLayout
        self.theCollectionView.register(UINib(nibName: "SomeNibName", bundle: nil), forCellWithReuseIdentifier: "Some Identifier")
        self.longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(self.handleLongGesture(gesture:)))
        self.theCollectionView.addGestureRecognizer(longPressGesture)
    

    fileprivate func moveDataItem(_ sIndex: Int, _ dIndex: Int) 
        let item = self.items.remove(at: sIndex)
        self.items.insert(item, at:dIndex)
        self.theCollectionView.reloadData()
    

    @objc private func handleLongGesture(gesture: UILongPressGestureRecognizer) 
        switch(gesture.state) 
        case UIGestureRecognizerState.began:
            guard let selectedIndexPath = self.theCollectionView.indexPathForItem(at: gesture.location(in: self.theCollectionView)) else 
                break
            
            self.theCollectionView.beginInteractiveMovementForItem(at: selectedIndexPath)

        case UIGestureRecognizerState.changed:
            guard let selectedIndexPath = self.theCollectionView.indexPathForItem(at: gesture.location(in: self.theCollectionView)) else 
                break
            
            self.theCollectionView?.updateInteractiveMovementTargetPosition(gesture.location(in: gesture.view!))

        case UIGestureRecognizerState.ended:
            self.theCollectionView.endInteractiveMovement()
        default:
            self.theCollectionView.cancelInteractiveMovement()
        
    



// MARK: - UICollectionViewDelegateFlowLayout
extension LoveProfileEditViewViewController: UICollectionViewDelegateFlowLayout 

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize 
        return CGSize(width: 88.0, height: collectionView.bounds.size.height)
    

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets 
        return UIEdgeInsetsMake(0.0, 5.0, 0.0, 5.0)
    

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat 
        return 10.0
    

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat 
        return 10.0
    

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize 
        return .zero
    

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize 
        return .zero
    


// MARK: - UICollectionViewDataSource
extension LoveProfileEditViewViewController: UICollectionViewDataSource 
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int 
        return self.items.count
    

    func collectionView(_ collectionView: UICollectionView, canMoveItemAt indexPath: IndexPath) -> Bool 
        //set boolean as per your need
        return true
    

    func collectionView(_ collectionView: UICollectionView, moveItemAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) 
        if sourceIndexPath.row > 0 && destinationIndexPath.row > 0 
            self.moveDataItem(sourceIndexPath.row, destinationIndexPath.row)
        
    

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell 
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Some Identifier", for: indexPath) as! SomeNibName
        cell.textLabel.text = self.items[indexPath.row]
        return cell
    

【讨论】:

我想我提到了objective-c 我正在使用平移手势来移动 UIViews。现在我怎么知道点击的视图是否到达了任何 UIView 的顶部? 如果您只需要重新订购,则无需考虑太多。对不起 swift 因为我比 Objective-c 更喜欢 swift :) 干杯伙伴,我希望它有所帮助。【参考方案3】:
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
[button addTarget:self action:@selector(imageTouch:withEvent:) 
forControlEvents:UIControlEventTouchDown];
[button addTarget:self action:@selector(imageMoved:withEvent:) 
forControlEvents:UIControlEventTouchDragInside];
[button setImage:[UIImage imageNamed:@"vehicle.png"] 
forState:UIControlStateNormal];
[self.view addSubview:button];

然后您可以通过响应 UIControlEventTouchDragInside 事件将车辆移动到您想要的任何位置,例如:

 - (IBAction) imageMoved:(id) sender withEvent:(UIEvent *) event
 
CGPoint point = [[[event allTouches] anyObject] locationInView:self.view];
UIControl *control = sender;
control.center = point;

【讨论】:

以上是关于如何拖动 UIView 元素并更改位置?的主要内容,如果未能解决你的问题,请参考以下文章

Angular2在拖动时更改可拖动元素的内容

自动布局打开时如何以编程方式更改 UIView 的位置

更改 react-beautiful-dnd 可拖动点击区域

计算 UIBezierPath 曲线控制点

在视图大小更改时更改 UIView 阴影大小会产生奇怪的效果

在“停止”事件期间如何定位克隆的可拖动元素?