首先是实现效果
1、建立UICollectionViewCell
创建cell,其中只有一个UILabel,为其添加长按事件,并设置一个简单的抖动动画
import UIKit
import Foundation
import SnapKit
protocol CellItemLongPressProtocol:class {
func cellItemLongPress(long:UILongPressGestureRecognizer)
}
class MyUIcollectionViewCell: UICollectionViewCell{
var titleUILabel: UILabel!
weak var delegate:CellItemLongPressProtocol?
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = #colorLiteral(red: 0.8039215803, green: 0.8039215803, blue: 0.8039215803, alpha: 1)
titleUILabel = UILabel(frame: frame)
titleUILabel.textColor = UIColor.black
titleUILabel.textAlignment = .center
self.contentView.addSubview(titleUILabel)
titleUILabel.snp.makeConstraints { (make) in
make.edges.equalToSuperview()
}
let longTap:UILongPressGestureRecognizer = UILongPressGestureRecognizer.init(target: self, action: #selector(longClick(long:)))
self.addGestureRecognizer(longTap)
}
@objc
func longClick(long:UILongPressGestureRecognizer) {
self.delegate?.cellItemLongPress(long: long)
print("longClick")
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
//抖动动画
extension MyUIcollectionViewCell{
func shakeAnimate() {
let animate:CABasicAnimation = CABasicAnimation.init(keyPath: "transform.rotation.z")
animate.duration = 0.1 //周期
animate.fromValue = -Double.pi/50
animate.toValue = Double.pi/50
animate.repeatCount = Float(LONG_MAX)
animate.autoreverses = true //恢复原样
self.layer.anchorPoint = CGPoint.init(x: 0.5, y: 0.5)
self.layer.add(animate, forKey: "shake")
}
func resetAnimate(){
self.layer.removeAnimation(forKey: "shake")
}
}
2、其次是显示以及拖动控制部分
建立数据源,生成50组数据
var resourceArray1:[[String:String]] = [[String:String]]()
for i in 1...50 {
var memu = [String:String]()
memu["title"] = "第\(i)个哈哈哈"
resourceArray1.append(memu)
}
显示cell
func createMenu(){
if uiCollectionView != nil{
uiCollectionView?.removeFromSuperview()
}
//计算图标宽度
width = UIScreen.main.bounds.width / (CGFloat(self.buttonColCount) + CGFloat(0.5))
//计算菜单视图高度
menuCollectionViewHeight = (width+10) * ceil(CGFloat(Float(resourceArray1.count) / Float(buttonColCount))) + CGFloat(40)
// 初始化
let layout = UICollectionViewFlowLayout.init()
layout.itemSize = CGSize(width: width, height: width)
layout.minimumLineSpacing = 10
layout.minimumInteritemSpacing = 10
layout.scrollDirection = .vertical
// 设置分区头视图和尾视图宽高
layout.headerReferenceSize = CGSize.init(width: UIScreen.main.bounds.width, height: CGFloat(40))
uiCollectionView = UICollectionView.init(frame: CGRect(x:0, y:0, width:UIScreen.main.bounds.width, height:menuCollectionViewHeight), collectionViewLayout: layout)
uiCollectionView?.backgroundColor = UIColor.white
uiCollectionView?.delegate = self
uiCollectionView?.dataSource = self
uiCollectionView?.allowsSelection = true
self.uiCollectionView.alwaysBounceVertical = true
self.uiCollectionView.alwaysBounceHorizontal = false
view.addSubview(uiCollectionView!)
uiCollectionView!.snp.makeConstraints { (make) -> Void in
make.edges.equalToSuperview()
}
// 注册cell
uiCollectionView?.register(MyUIcollectionViewCell.self, forCellWithReuseIdentifier: "cell")
}
填充数据
extension MyUICollectionViewViewController:UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return resourceArray1.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell:MyUIcollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! MyUIcollectionViewCell
cell.titleUILabel.text = resourceArray1[indexPath.item]["title"]
cell.titleUILabel.numberOfLines = 0
cell.titleUILabel.lineBreakMode = .byCharWrapping
cell.delegate = self
return cell
}
}
抖动动画
extension MyUICollectionViewViewController{
func colllectionViewAnimateCell(isShake:Bool){
for cell in uiCollectionView.visibleCells {
let newcell = cell as! MyUIcollectionViewCell
if isShake{
newcell.shakeAnimate()
}else{
newcell.resetAnimate()
}
}
}
}
长按拖动部分
//长按
extension MyUICollectionViewViewController:CellItemLongPressProtocol{
func cellItemLongPress(long: UILongPressGestureRecognizer) {
print("cellItemLongPress")
let cell:MyUIcollectionViewCell = long.view as! MyUIcollectionViewCell
if long.state == .began {//长按开始
longPressedView = cell.snapshotView(afterScreenUpdates: true)
longPressedView?.center = cell.center
uiCollectionView.addSubview(longPressedView!)
indexPath = uiCollectionView.indexPath(for: cell)!
originCell = cell
originCell.isHidden = true
startPoint = long.location(in: uiCollectionView)
colllectionViewAnimateCell(isShake: true)
}else if long.state == .changed {
//横线偏移量
let tranx: CGFloat = long.location(ofTouch: 0, in: uiCollectionView).x - startPoint.x
//纵向偏移量
let trany:CGFloat = long.location(ofTouch: 0, in: uiCollectionView).y - startPoint.y
//跟随手指移动
longPressedView?.center = __CGPointApplyAffineTransform((longPressedView?.center)!, CGAffineTransform.init(translationX: tranx, y: trany))
//更新当前移动结果
startPoint = long.location(ofTouch: 0, in: uiCollectionView)
//计算当前移动的cell和当前所处位置的cell位置,判断是否需要交换
for cell in uiCollectionView.visibleCells {
//跳过当前拖动的那个cell
if uiCollectionView.indexPath(for: cell) == indexPath {
continue
}
//计算横线偏移量和纵向偏移量所对应的斜边的长度
let space:CGFloat = sqrt(pow(longPressedView!.center.y - cell.center.y, 2) + pow(longPressedView!.center.x - cell.center.x, 2))
if space <= longPressedView!.bounds.width * 0.5 && (abs(longPressedView!.center.x - cell.center.x) < longPressedView!.bounds.width * 0.5){
nextIndexPath = uiCollectionView.indexPath(for: cell)!
//如果是往后移动,先插入,再移除
if nextIndexPath.item > indexPath.item {
let menu = resourceArray1[indexPath.item]
resourceArray1.insert(menu, at: nextIndexPath.item)
resourceArray1.remove(at: indexPath.item)
}else {
//如果是往前移,先移除,再插入
let menu = resourceArray1[indexPath.item]
resourceArray1.remove(at: indexPath.item)
resourceArray1.insert(menu, at: nextIndexPath.item)
}
//移动
uiCollectionView.moveItem(at: indexPath, to: nextIndexPath)
indexPath = nextIndexPath
break
}
}
}else if long.state == .ended{
longPressedView?.removeFromSuperview()
originCell.isHidden = false
colllectionViewAnimateCell(isShake: false)
}
}
}