【问题标题】:Keep cell rotation when swapping cells in collection view在集合视图中交换单元格时保持单元格旋转
【发布时间】:2018-04-10 18:01:08
【问题描述】:

我有一个 3 x 3 网格中有 9 个单元格的集合视图。我可以使用这个问题的答案代码交换单元格 - Custom Cell Reorder Behavior in CollectionView,我还可以使用

旋转单元格

如果让 indexPath = self.collectionView?.indexPathForItem(at: sender.location(in: self.collectionView)) {

let cell = self.collectionView?.cellForItem(at: indexPath)

cell?.transform = (cell?.transform.rotated(by: _direction))!

}

当我旋转一个单元格然后将其与另一个单元格交换时,问题就出现了。旋转重置,单元格在交换后恢复到其原始位置(0 度)。

我希望能够旋转单元格然后交换它们而不会失去旋转。

编辑: 这是我在 View Controller 中的旋转函数以及用于交换单元格的 handleLongGesture 函数:

@IBAction func userSwippedRight(_ sender: UISwipeGestureRecognizer) {
    rotate(_direction: CGFloat(Double.pi / 2), sender: sender)
}

@IBAction func userSwippedLeft(_ sender: UISwipeGestureRecognizer) {
    rotate(_direction: CGFloat(-Double.pi / 2), sender: sender)
}

func rotate(_direction: CGFloat, sender: UISwipeGestureRecognizer ) {

UIView.animate(withDuration: 0.25) {
        if let indexPath = self.collectionView?.indexPathForItem(at: sender.location(in: self.collectionView)) {

            let cell = self.collectionView?.cellForItem(at: indexPath)

            cell?.transform = (cell?.transform.rotated(by: _direction))!


            let radians:Float = atan2f(Float(cell!.transform.b), Float(cell!.transform.a))
            var degrees:Int = Int(radians * Float(180 / Double.pi))

            if(degrees == -180)
            {
                degrees = 180
            }

            print(degrees)

        } else {
            print("Swipe Registered")

        }
    }   
}


func handleLongGesture(_ gesture: UILongPressGestureRecognizer) {

    switch(gesture.state) {

    case UIGestureRecognizerState.began:
        guard let selectedIndexPath = self.collectionView?.indexPathForItem(at: gesture.location(in: self.collectionView)) else {
            break
        }
        collectionView?.beginInteractiveMovementForItem(at: selectedIndexPath)
    case UIGestureRecognizerState.changed:
        collectionView?.updateInteractiveMovementTargetPosition(gesture.location(in: gesture.view!))
    case UIGestureRecognizerState.ended:
        collectionView?.endInteractiveMovement()
    default:
        collectionView?.cancelInteractiveMovement()
    }
}

下面是 UICollectionView 的子类,我在其中为单元格的交互式移动添加了自定义处理。

import UIKit

    extension UIView {
        func snapshot() -> UIImage {
            UIGraphicsBeginImageContext(self.bounds.size)
            self.layer.render(in: UIGraphicsGetCurrentContext()!)
            let image = UIGraphicsGetImageFromCurrentImageContext()
            UIGraphicsEndImageContext()
            return image!
        }
    }

    extension CGPoint {
        func distanceToPoint(p:CGPoint) -> CGFloat {
            return sqrt(pow((p.x - x), 2) + pow((p.y - y), 2))
        }
    }

    struct SwapDescription : Hashable {
        var firstItem : Int
        var secondItem : Int

        var hashValue: Int {
            get {
                return (firstItem * 10) + secondItem
            }
        }
    }

    func ==(lhs: SwapDescription, rhs: SwapDescription) -> Bool {
        return lhs.firstItem == rhs.firstItem && lhs.secondItem == rhs.secondItem
    }

    class SwappingCollectionView: UICollectionView {

        var interactiveCell = UICollectionViewCell()
        var myView : UICollectionView?
        var interactiveIndexPath : NSIndexPath?
        var interactiveView : UIView?
        var swapSet : Set<SwapDescription> = Set()
        var previousPoint : CGPoint?

        static let distanceDelta:CGFloat = 2 // adjust as needed


        override func beginInteractiveMovementForItem(at indexPath: IndexPath) -> Bool {

            self.interactiveIndexPath = indexPath as NSIndexPath?

            self.interactiveCell = self.cellForItem(at: indexPath as IndexPath) as! CustomCellCollectionViewCell

            self.interactiveCell.transform = CGAffineTransform(scaleX: 1.05, y: 1.05)

            self.interactiveView = UIImageView(image: self.interactiveCell.snapshot())

            self.interactiveView?.frame = self.interactiveCell.frame

            self.addSubview(self.interactiveView!)
            self.bringSubview(toFront: self.interactiveView!)

            self.interactiveCell.isHidden = true

            self.interactiveCell.transform = CGAffineTransform.identity

            return true
        }


        override func updateInteractiveMovementTargetPosition(_ targetPosition: CGPoint) {

            if (self.shouldSwap(newPoint: targetPosition)) {

                if let hoverIndexPath = self.indexPathForItem(at: targetPosition), let interactiveIndexPath = self.interactiveIndexPath {

                    let swapDescription = SwapDescription(firstItem: interactiveIndexPath.item, secondItem: hoverIndexPath.item)

                    if (!self.swapSet.contains(swapDescription)) {

                        self.swapSet.insert(swapDescription)

                        self.performBatchUpdates({
                            self.moveItem(at: interactiveIndexPath as IndexPath, to: hoverIndexPath)
                            self.moveItem(at: hoverIndexPath, to: interactiveIndexPath as IndexPath)
                        }, completion: {(finished) in
                            self.swapSet.remove(swapDescription)

                            self.dataSource?.collectionView!(self, moveItemAt: interactiveIndexPath as IndexPath, to: hoverIndexPath as IndexPath)

                            self.interactiveIndexPath = hoverIndexPath as NSIndexPath?
                        })
                    }
                }
            }

            self.interactiveView?.center = targetPosition
            self.previousPoint = targetPosition
        }

        override func endInteractiveMovement() {
            // Save the last rotation
            self.cleanup()
        }

        override func cancelInteractiveMovement() {
            self.cleanup()
        }

        func cleanup() {

            self.interactiveCell.isHidden = false
            self.interactiveView?.removeFromSuperview()
            self.interactiveView = nil
            self.interactiveCell.transform = CGAffineTransform.identity
            self.interactiveIndexPath = nil
            self.previousPoint = nil
            self.swapSet.removeAll()
        }

        func shouldSwap(newPoint: CGPoint) -> Bool {
            if let previousPoint = self.previousPoint {
                let distance = previousPoint.distanceToPoint(p: newPoint)
                return distance < SwappingCollectionView.distanceDelta
            }

            return false
        }

    }

我的 collectionViewCell 子类

import UIKit
import Firebase
import FirebaseDatabase

class CustomCollectionViewCell: UICollectionViewCell {

    @IBOutlet weak var imageView: UIImageView!


}

【问题讨论】:

    标签: ios swift uicollectionview


    【解决方案1】:

    您应该将旋转状态存储在某处并将其应用到cellForItem(at:)。如需进一步帮助,我需要您的视图控制器提供更多代码。

    【讨论】:

    • 我在上面添加了我的代码。希望这可以帮助?谢谢。
    【解决方案2】:

    我建议不要操纵单元格的变换。我会设置UICollectionViewCell 的自定义子类并将所有内容放在内容视图中并旋转它。

    我还会给每个自定义单元格一个currentRotation 属性,并使其与变换的旋转保持同步。当您获取一个单元格或将一个单元格出列时,检查它的 currentRotation 属性并使用它来查看它是否需要旋转。

    【讨论】:

    • 我对 swift 还很陌生。您介意为我提供一些可以帮助我执行此操作的代码吗?
    • 我没有这样的代码,也没有时间写。把我的建议分成几个步骤,一次一个地解决。如果遇到困难,请回复问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-06
    相关资源
    最近更新 更多