【问题标题】:Custom Drag&Drop UICollectionViewLayout snap to a grid自定义拖放 UICollectionViewLayout 捕捉到网格
【发布时间】:2018-03-03 10:41:09
【问题描述】:

我正在开发一个应用程序,我可以在其中跟踪我的青年足球队的替换情况。

按照Payal Gupta 的关于拖放到集合和表格中的教程,我设法在两个集合视图(PlayersOntoTheField 和 Substitutes)之间进行拖放操作 Screenshot

当我将一名替补球员拖入我的操场时,它现在应该会捕捉到预定义的球队阵容(例如屏幕截图中的 3-2-1)。是否有可能通过自定义 UICollectionViewLayout 获得这种行为,或者有人有其他建议吗?

非常感谢您提前提供的任何帮助。

丹尼

//Based on a work by: 
//Payal Gupta (https://github.com/pgpt10/DragAndDrop-CollectionView)

import UIKit

class ViewController: UIViewController
{
    private var substitutes = ["player1", "player2", "player3", "player4"]
    private var players = [String]()

    @IBOutlet weak var substitutesCollectionView: UICollectionView!
    @IBOutlet weak var playersCollectionView: UICollectionView!

    override func viewDidLoad()
    {
        super.viewDidLoad()

        //SubstitutesCollectionView drag and drop configuration
        self.substitutesCollectionView.dragInteractionEnabled = true
        self.substitutesCollectionView.dragDelegate = self
        self.substitutesCollectionView.dropDelegate = self

        //PlayersCollectionView drag and drop configuration
        self.playersCollectionView.dragInteractionEnabled = true
        self.playersCollectionView.dropDelegate = self
        self.playersCollectionView.dragDelegate = self
        self.playersCollectionView.reorderingCadence = .fast //default value - .immediate
    }

    //MARK: Private Methods
    private func reorderItems(coordinator: UICollectionViewDropCoordinator, destinationIndexPath: IndexPath, collectionView: UICollectionView)
    {
        let items = coordinator.items
        if items.count == 1, let item = items.first, let sourceIndexPath = item.sourceIndexPath
        {
            var dIndexPath = destinationIndexPath
            if dIndexPath.row >= collectionView.numberOfItems(inSection: 0)
            {
                dIndexPath.row = collectionView.numberOfItems(inSection: 0) - 1
            }
            collectionView.performBatchUpdates({
                if collectionView === self.playersCollectionView
                {
                    self.players.remove(at: sourceIndexPath.row)
                    self.players.insert(item.dragItem.localObject as! String, at: dIndexPath.row)
                }
                else
                {
                    self.substitutes.remove(at: sourceIndexPath.row)
                    self.substitutes.insert(item.dragItem.localObject as! String, at: dIndexPath.row)
                }
                collectionView.deleteItems(at: [sourceIndexPath])
                collectionView.insertItems(at: [dIndexPath])
            })
            coordinator.drop(items.first!.dragItem, toItemAt: dIndexPath)
        }
    }

    private func copyItems(coordinator: UICollectionViewDropCoordinator, destinationIndexPath: IndexPath, collectionView: UICollectionView)
    {
        collectionView.performBatchUpdates({
            var indexPaths = [IndexPath]()
            for (index, item) in coordinator.items.enumerated()
            {
                let indexPath = IndexPath(row: destinationIndexPath.row + index, section: destinationIndexPath.section)
                if collectionView === self.playersCollectionView
                {
                    self.players.insert(item.dragItem.localObject as! String, at: indexPath.row)
                }
                else
                {
                    self.substitutes.insert(item.dragItem.localObject as! String, at: indexPath.row)
                }
                indexPaths.append(indexPath)
            }
            collectionView.insertItems(at: indexPaths)
        })
    }
}

// MARK: - UICollectionViewDataSource Methods
extension ViewController : UICollectionViewDataSource
{
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
    {
        return collectionView == self.substitutesCollectionView ? self.substitutes.count : self.players.count
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
    {
        if collectionView == self.substitutesCollectionView
        {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell1", for: indexPath) as! MyCollectionViewCell
            cell.customImageView?.image = UIImage(named: self.substitutes[indexPath.row])
            cell.customLabel.text = self.substitutes[indexPath.row].capitalized
            return cell
        }
        else
        {
            let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell2", for: indexPath) as! MyCollectionViewCell
            cell.customImageView?.image = UIImage(named: self.players[indexPath.row])
            cell.customLabel.text = self.players[indexPath.row].capitalized
            return cell
        }
    }
}

// MARK: - UICollectionViewDragDelegate Methods
extension ViewController : UICollectionViewDragDelegate
{
    func collectionView(_ collectionView: UICollectionView, itemsForBeginning session: UIDragSession, at indexPath: IndexPath) -> [UIDragItem]
    {
        let item = collectionView == substitutesCollectionView ? self.substitutes[indexPath.row] : self.players[indexPath.row]
        let itemProvider = NSItemProvider(object: item as NSString)
        let dragItem = UIDragItem(itemProvider: itemProvider)
        dragItem.localObject = item
        return [dragItem]
    }

    func collectionView(_ collectionView: UICollectionView, itemsForAddingTo session: UIDragSession, at indexPath: IndexPath, point: CGPoint) -> [UIDragItem]
    {
        let item = collectionView == substitutesCollectionView ? self.substitutes[indexPath.row] : self.players[indexPath.row]
        let itemProvider = NSItemProvider(object: item as NSString)
        let dragItem = UIDragItem(itemProvider: itemProvider)
        dragItem.localObject = item
        return [dragItem]
    }

    func collectionView(_ collectionView: UICollectionView, dragPreviewParametersForItemAt indexPath: IndexPath) -> UIDragPreviewParameters?
    {
        if collectionView == substitutesCollectionView
        {
            let previewParameters = UIDragPreviewParameters()
            previewParameters.visiblePath = UIBezierPath(rect: CGRect(x: 15, y: 5, width: 30, height: 30))
            return previewParameters
        }
        return nil
    }
}

// MARK: - UICollectionViewDropDelegate Methods
extension ViewController : UICollectionViewDropDelegate
{
    func collectionView(_ collectionView: UICollectionView, canHandle session: UIDropSession) -> Bool
    {
        return session.canLoadObjects(ofClass: NSString.self)
    }

    func collectionView(_ collectionView: UICollectionView, dropSessionDidUpdate session: UIDropSession, withDestinationIndexPath destinationIndexPath: IndexPath?) -> UICollectionViewDropProposal
    {
        if collectionView === self.substitutesCollectionView
        {
            if collectionView.hasActiveDrag
            {
                return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
            }
            else
            {
                return UICollectionViewDropProposal(operation: .forbidden)
            }
        }
        else
        {
            if collectionView.hasActiveDrag
            {
                return UICollectionViewDropProposal(operation: .move, intent: .insertAtDestinationIndexPath)
            }
            else
            {
                return UICollectionViewDropProposal(operation: .copy, intent: .insertAtDestinationIndexPath)
            }
        }
    }

    func collectionView(_ collectionView: UICollectionView, performDropWith coordinator: UICollectionViewDropCoordinator)
    {
        let destinationIndexPath: IndexPath
        if let indexPath = coordinator.destinationIndexPath
        {
            destinationIndexPath = indexPath
        }
        else
        {
            // Get last index path of table view.
            let section = collectionView.numberOfSections - 1
            let row = collectionView.numberOfItems(inSection: section)
            destinationIndexPath = IndexPath(row: row, section: section)
        }

        switch coordinator.proposal.operation
        {
        case .move:
            self.reorderItems(coordinator: coordinator, destinationIndexPath:destinationIndexPath, collectionView: collectionView)
            break

        case .copy:
            self.copyItems(coordinator: coordinator, destinationIndexPath: destinationIndexPath, collectionView: collectionView)

        default:
            return
        }
    }
}

【问题讨论】:

    标签: swift drag-and-drop uicollectionview uicollectionviewlayout custom-view


    【解决方案1】:

    到目前为止,我对自定义 UICollectionViewLayout 的解决方法:

    import UIKit
    
    class LineUp_3_2_1View: UICollectionViewLayout {
    
        private var center: CGPoint!
        private var itemSize: CGSize!
        private var radiusOfCircleViews: CGFloat!
        private var numberOfItems: Int!
    
        override func prepare() {
            super.prepare()
    
            guard let collectionView = collectionView else { return }
    
            radiusOfCircleViews = CGFloat(30.0)
            itemSize = CGSize(width: radiusOfCircleViews * 2, height: radiusOfCircleViews * 2)
            center = CGPoint(x: collectionView.bounds.midX, y: collectionView.bounds.midY)
            numberOfItems = collectionView.numberOfItems(inSection: 0)
        }
    
        override var collectionViewContentSize: CGSize {
            return collectionView!.bounds.size
        }
    
        override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
            let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
    
            if (indexPath.item == 0) {attributes.center = CGPoint(x: 169, y: 344)}
            if (indexPath.item == 1) {attributes.center = CGPoint(x: 46, y: 250)}
            if (indexPath.item == 2) {attributes.center = CGPoint(x: 169, y: 250)}
            if (indexPath.item == 3) {attributes.center = CGPoint(x: 287, y: 250)}
            if (indexPath.item == 4) {attributes.center = CGPoint(x: 80, y: 156)}
            if (indexPath.item == 5) {attributes.center = CGPoint(x: 253, y: 156)}
            if (indexPath.item == 6) {attributes.center = CGPoint(x: 169, y: 62)}
    
            attributes.size = itemSize
    
            return attributes
        }
    
        override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
            return (0 ..< collectionView!.numberOfItems(inSection: 0))
                .flatMap { item -> UICollectionViewLayoutAttributes? in    // `compactMap` in Xcode 9.3
                    self.layoutAttributesForItem(at: IndexPath(item: item, section: 0))
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2020-12-20
      • 2014-01-08
      • 1970-01-01
      • 2012-03-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多