ネットでLongPressでUITableViewのCellを移動する文章がありますが、Sectionの間に移動する例はなかなか無いです。今日はその経験を共有しましょう。
実現する方法##
1.長押した時、押した場所によって、該当Cellを取得し、IndexPathを変数originIndexPathに渡す。そして、綺麗な動き見えるためにスナップショットを作成して該当Cellを見えないように設定。
2.指が押しながら移動する時、スナップショットの座標Y軸を更新し、新しい位置のCellのIndexPathが元のIndexPathと違うとoriginIndexPathを更新し、データも更新。
3.リリースした時、該当Cellを見えるように設定して、スナップショットを削除。
重要ポイント:
移動の処理について、セクションが変わる場合、もしセクションの一番下から入る時、そのままIndexPathを変数originIndexPathに渡す前に、IndexPathに1行を追加することが必要。
画面操作##
Main.storyboardの画面で、LibrayからLong Press Gesture Reconigerをドラグして、UITableVIewのCellの上に置きます。
コード##
UITableViewController
import UIKit
import CoreData
class CatalogViewController: UITableViewController{
//CellのIndexPathを臨時保存用変数
var originIndexPath: IndexPath?
//スナップショットの変数
var initialSnapshot: UIView?
//長押しジェスチャーの処理
@IBAction func LongPress(_ sender: UILongPressGestureRecognizer) {
//ジェスチャーの状態を取得
let state = sender.state
//指の位置を取得
let location = sender.location(in: tableView)
//指所在のCellのIndexPathを取得
guard let indexPath = self.tableView.indexPathForRow(at: location) else { return }
switch state {
//最初押した時の処理
case .began:
originIndexPath = indexPath
guard let cell = self.tableView.cellForRow(at: indexPath) else { return }
initialSnapshot = cellSnapshot(inputView: cell)
guard let snapshot = initialSnapshot else { return }
var center = cell.center
snapshot.center = center
snapshot.alpha = 0.0
self.tableView.addSubview(snapshot)
UIView.animate(withDuration: 0.25, animations: {
center.y = location.y
snapshot.center = center
snapshot.transform = CGAffineTransform(scaleX: 1.05, y: 1.05)
snapshot.alpha = 0.98
cell.alpha = 0.0
}, completion:{(finished) in cell.isHidden = true })
//指が移動する時の処理
case .changed:
guard let snapshot = initialSnapshot else { return }
var center = snapshot.center
center.y = location.y
snapshot.center = center
guard let sourceIndexPath = originIndexPath else { return }
if indexPath.section != sourceIndexPath.section {
//IndexPathの更新
if indexPath.row + 1 == tableView.numberOfRows(inSection: indexPath.section){
originIndexPath = IndexPath(row: indexPath.row + 1, section: indexPath.section)
}else{ originIndexPath = indexPath }
//データの更新、自身のプロジェクトによって修正が必要になります。
let cataitem = fetchedResultsController.object(at: sourceIndexPath )
cataitem.category = NSNumber(value: indexPath.section).boolValue
saveContext()
}
//IndexPathの更新
else if indexPath.row != sourceIndexPath.row {
tableView.moveRow(at: sourceIndexPath, to: indexPath)
originIndexPath = indexPath
}
//指が離れた時の処理
default:
guard let cell = self.tableView.cellForRow(at: originIndexPath!) else {return}
guard let snapshot = initialSnapshot else {return}
cell.isHidden = false
cell.alpha = 0.0
UIView.animate(withDuration: 0.25, animations: {
snapshot.center = cell.center
snapshot.transform = CGAffineTransform.identity
snapshot.alpha = 0
cell.alpha = 1
}, completion: { (finished) -> Void in
if finished {
self.originIndexPath = nil
snapshot.removeFromSuperview()
self.initialSnapshot = nil
}})
}
}
//スナップショットの作成関数
private func cellSnapshot(inputView: UIView) -> UIView? {
UIGraphicsBeginImageContextWithOptions(inputView.bounds.size, false, 0)
if let CurrentContext = UIGraphicsGetCurrentContext() {
inputView.layer.render(in: CurrentContext)
}
guard let image = UIGraphicsGetImageFromCurrentImageContext() else {
UIGraphicsEndImageContext()
return nil
}
UIGraphicsEndImageContext()
let snapshot = UIImageView(image: image)
snapshot.layer.masksToBounds = false
snapshot.layer.cornerRadius = 0
snapshot.layer.shadowOffset = CGSize(width: -5, height: 0)
snapshot.layer.shadowRadius = 5
snapshot.layer.shadowOpacity = 0.4
return snapshot
}
以上です、Have fun!