简体   繁体   中英

Swift - Movable rows in tableView only within a section, not between

Is there a way to prevent cells in a tableView from being moved to a different section?

The sections have data for different types of cells, so the app crashes when the user tries to drag a cell into a different section.

I would like to only allow the user to move a cell inside the section, and not in between sections.

Relevant code is below:

override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
    return true
}

override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
    let reorderedRow = self.sections[sourceIndexPath.section].rows.remove(at: sourceIndexPath.row)
    self.sections[destinationIndexPath.section].rows.insert(reorderedRow, at: destinationIndexPath.row)

    self.sortedSections.insert(sourceIndexPath.section)
    self.sortedSections.insert(destinationIndexPath.section)
}

You will need to implement the UITableViewDelegate method targetIndexPathForMoveFromRowAt .

Your strategy will be to allow the move if the source and destination section are the same. If they aren't then you can return either row 0, if the proposed destination section is less than the source section or the last row of the section if the proposed destination section is greater than the source section.

This will constrain the move to the source section.

override func tableview(_ tableView: UITableView, targetIndexPathForMoveFromRowAt sourceIndexPath: IndexPath, toProposedIndexPath proposedDestinationIndexPath: IndexPath) -> IndexPath {

    let sourceSection = sourceIndexPath.section
    let destSection = proposedDestinationIndexPath.section

    if destSection < sourceSection {
        return IndexPath(row: 0, section: sourceSection)
    } else if destSection > sourceSection {
        return IndexPath(row: self.tableView(tableView, numberOfRowsInSection:sourceSection)-1, section: sourceSection)
    }

    return proposedDestinationIndexPath
}

You can retarget the proposed destination for restriction by implementing the tableView:targetIndexPathForMoveFromRowAtIndexPath:toProposedIndexPath: method

  func tableView(_ tableView: UITableView, targetIndexPathForMoveFromRowAt sourceIndexPath: IndexPath, toProposedIndexPath proposedDestinationIndexPath: IndexPath) -> IndexPath {

    // Finds number of items in source group
    let numberOfItems = self.tableView(tableView, numberOfRowsInSection: sourceIndexPath.section)

    // Restricts rows to relocation in their own group by checking source and destination sections
    if (sourceIndexPath.section != proposedDestinationIndexPath.section) {

      /*
       if we move the row to the not allowed upper area, it is moved to the top of the allowed group and vice versa
       if we move the row to the not allowed lower area, it is moved to the bottom of the allowed group
       also prevents moves to the last row of a group (which is reserved for the add-item placeholder).
      */
      let rowInSourceSection = (sourceIndexPath.section > proposedDestinationIndexPath.section) ? 0 : numberOfItems - 1;

      return IndexPath(row: rowInSourceSection, section: sourceIndexPath.section)
    }
    // Prevents moves to the last row of a group (which is reserved for the add-item placeholder).
    else if (proposedDestinationIndexPath.row >= numberOfItems) {

      return IndexPath(row: numberOfItems - 1, section: sourceIndexPath.section)
    }
    // Passing all restrictions
    return proposedDestinationIndexPath
  }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM