How to drag a static cell to a view swift table?

I have one tableView in my storyBoard, where I added 4 static cells to it, and my storyBoard looks like this:

enter image description here

I have no data source for this tableView , because my cells are static.

And I use the code below to drag and drop a cell, and it works fine until I scroll through the table.

 import UIKit class TableViewController: UITableViewController { var sourceIndexPath: NSIndexPath = NSIndexPath() var snapshot: UIView = UIView() let longPress: UILongPressGestureRecognizer = { let recognizer = UILongPressGestureRecognizer() return recognizer }() override func viewDidLoad() { super.viewDidLoad() longPress.addTarget(self, action: "longPressGestureRecognized:") self.tableView.addGestureRecognizer(longPress) self.tableView.allowsSelection = false } override func viewWillAppear(animated: Bool) { self.tableView.reloadData() } // MARK: UIGestureRecognizer func longPressGestureRecognized(gesture: UILongPressGestureRecognizer){ let state: UIGestureRecognizerState = gesture.state let location:CGPoint = gesture.locationInView(self.tableView) if let indexPath: NSIndexPath = self.tableView.indexPathForRowAtPoint(location){ switch(state){ case UIGestureRecognizerState.Began: sourceIndexPath = indexPath let cell: UITableViewCell = self.tableView .cellForRowAtIndexPath(indexPath)! //take a snapshot of the selected row using helper method snapshot = customSnapshotFromView(cell) //add snapshot as subview, centered at cell center var center: CGPoint = cell.center snapshot.center = center snapshot.alpha = 0.0 self.tableView.addSubview(snapshot) UIView.animateWithDuration(0.25, animations: { () -> Void in center.y = location.y self.snapshot.center = center self.snapshot.transform = CGAffineTransformMakeScale(1.05, 1.05) self.snapshot.alpha = 0.98 cell.alpha = 0.0 }, completion: { (finished) in cell.hidden = true }) case UIGestureRecognizerState.Changed: let cell: UITableViewCell = self.tableView.cellForRowAtIndexPath(indexPath)! var center: CGPoint = snapshot.center center.y = location.y snapshot.center = center print("location \(location.y)") //is destination valid and is it different form source? if indexPath != sourceIndexPath{ //update data source //I have commented this part because I am not using any dataSource. // self.customArray.exchangeObjectAtIndex(indexPath.row, withObjectAtIndex: sourceIndexPath.row) //move the row self.tableView.moveRowAtIndexPath(sourceIndexPath, toIndexPath: indexPath) //and update source so it is in sync with UI changes sourceIndexPath = indexPath } if (location.y < 68) || (location.y > 450) { print("cancelled") self.snapshot.alpha = 0.0 cell.hidden = false UIView.animateWithDuration(0.10, animations: { () -> Void in self.snapshot.center = cell.center self.snapshot.transform = CGAffineTransformIdentity self.snapshot.alpha = 0.0 //undo fade out cell.alpha = 1.0 }, completion: { (finished) in self.snapshot.removeFromSuperview() }) } case UIGestureRecognizerState.Ended: //clean up print("ended") let cell: UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)! cell.hidden = false UIView.animateWithDuration(0.25, animations: { () -> Void in self.snapshot.center = cell.center self.snapshot.transform = CGAffineTransformIdentity self.snapshot.alpha = 0.0 //undo fade out cell.alpha = 1.0 }, completion: { (finished) in self.snapshot.removeFromSuperview() }) break default: break } }else{ gesture.cancelsTouchesInView = true } } func customSnapshotFromView(inputView: UIView) -> UIView { // Make an image from the input view. UIGraphicsBeginImageContextWithOptions(inputView.bounds.size, false, 0) inputView.layer.renderInContext(UIGraphicsGetCurrentContext()!) let image = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext(); // Create an image view. let snapshot = UIImageView(image: image) snapshot.layer.masksToBounds = false snapshot.layer.cornerRadius = 0.0 snapshot.layer.shadowOffset = CGSize(width: -5.0, height: 0.0) snapshot.layer.shadowRadius = 5.0 snapshot.layer.shadowOpacity = 0.4 return snapshot } } 

When I scroll after dragging and dropping, it looks like this:

enter image description here

As you can see, the cell does not appear again. I want to drag a static cell, and I want to keep its position, so I won’t switch again when scrolling.

An example for more information.

This is just a demo project. But I added a lot of elements to my cell, and each cell has different interfaces.

+6
source share
4 answers

There is a library that does exactly what you want to do with a very similar approach. It was called FMMoveTableView , but for cells with a data source.

I think the cause of your problem is that when you move the cells around and then scroll the data source from the storyboard, it no longer synchronizes with the table, and therefore your cell object cannot be redrawn.

I think you should implement your table as follows:

  • Make your 4 cells custom.
  • Subclass each.
  • Create an array with numbers from 1 to 4
  • Reorder array while dragging and dropping
  • Override cellForRowAtIndexPath to display the right cell for the correct number.
+2
source

You can drag and drop a uitableview cell from uitableview delegates ....... 1) set the table view edit style to its none.

2) implement the table view delegate to enable drag and drop methods ie canMoveRowAtIndexPath.

+2
source

You can create several dynamic cells. You just need to remove the cells with the correct id.

+1
source

Are you only doing this for layout purposes, maybe a UICollectionView or a custom UIScrollView can do the job?


However, I have a solution:

  • Create an IBOutlet Collection Containing All Your Static UITableViewCell s
  • Create an index list to simulate a "data source"
  • Override cellForRowAtIndexPath for drawing using custom index list
  • When updating the order of the list, update the indexList so that the view "remembers" this change

This table view controller explains all this:

 class TableViewController: UITableViewController { @IBOutlet var outletCells: [UITableViewCell]! var indexList = [Int]() override func viewDidLoad() { super.viewDidLoad() // Prepare a index list. // We will move positions in this list instead // of trying to move the view postions. for (index, _) in outletCells.enumerate() { indexList.append(index) } } override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { // Use dynamic count, not needed I guess but // feels better this way. return outletCells.count } override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { // Use the index path to get the true index and return // the view on that index in our IBOutlet collection let realIndexForPos = indexList[indexPath.row] return outletCells[realIndexForPos] } @IBAction func onTap(sender: AnyObject) { // Simulating your drag n drop stuff here... :) let swapThis = 1 let swapThat = 2 tableView.moveRowAtIndexPath(NSIndexPath(forItem: swapThis, inSection: 0), toIndexPath: NSIndexPath(forItem: swapThat, inSection: 0)) // Update the indexList as this is the "data source" // Do no use moveRowAtIndexPath as this is never triggred // This one line works: swap(&indexList[swapThis], &indexList[swapThat]) // But bellow is easier to understand let tmpVal = indexList[swapThis] indexList[swapThis] = indexList[swapThat] indexList[swapThat] = tmpVal } } 

To create an IBOutlet use Interface Builder. Use the Referencing Outlet Collection in each table view cell and drag the same @IBOutlet for each of them into your controller code.

enter image description here

+1
source

All Articles