开发者

Reordering controls on UITableView while not in editing mode?

I have a UITableView and I want to be able to reorder the rows when I'm not in edit mode, meaning I don't want 开发者_运维技巧to see the delete icons until I press Edit. I want to be able to see and use the reordering controls all the time. Is that possible?

Do I have to keep the UITableView in editing mode all the time and enable/disable the delete icon manually? How to disable the swipe to delete in that case?


I found a solution. UITableViewCell refuses to draw the reorder control unless it's in editing mode. Fortunately, UITableViewCell and UITableView track editing separately, and crucially, UITableView actually handles reordering regardless of its own editing mode. We just need to trick the cells into drawing the reorder controls and we're home free.

Subclass UITableViewCell like this:

class ReorderTableViewCell: UITableViewCell {

    override var showsReorderControl: Bool {
        get {
            return true // short-circuit to on
        }
        set { }
    }

    override func setEditing(editing: Bool, animated: Bool) {
        if editing == false {
            return // ignore any attempts to turn it off
        }

        super.setEditing(editing, animated: animated)
    }

}

Now simply set editing = true on cells for which you want to enable reordering. You can make it conditional on -tableView:canMoveRowAtIndexPath:.

In your table view data source:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath)

    // Configure the cell...
   :

    cell.editing = self.tableView(tableView, canMoveRowAtIndexPath: indexPath) // conditionally enable reordering

    return cell
}

The only drawback is that this is incompatible with the table view allowsMultipleSelectionDuringEditing option; the edit control is incorrectly always shown. A workaround is to enable multiple selection only during actual table view editing.

In your table view controller:

override func setEditing(editing: Bool, animated: Bool) {
    super.setEditing(editing, animated: animated)

    self.tableView.allowsMultipleSelectionDuringEditing = editing // enable only during actual editing to avoid cosmetic problem
}

Also, in -viewDidLoad or your storyboard, set the initial value of allowsMultipleSelectionDuringEditing to false.


Reorder without deletion and no indentation.

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    return YES;
}

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath{
    return UITableViewCellEditingStyleNone; 
}

- (BOOL)tableView:(UITableView *)tableview shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath {
    return NO;
}


- (BOOL)tableView:(UITableView *)tableview canMoveRowAtIndexPath:(NSIndexPath *)indexPath {
    return YES;
}

Reference: Solution posted by Stefan von Chossy here


As far as I'm aware you can't do it using just the editing flag. However, it's not hard to achieve a similar effect.

Have your own boolean ie deleting. Set the tableview cell to cell.showsReorderControl = YES. Then implement all the methods required for moving cells. The bit of code I think you're looking for is. – tableView:editingStyleForRowAtIndexPath: if deleting == YES return UITableViewCellEditingStyleDelete otherwise return UITableViewCellEditingStyleNone. Finally, set tableView.editing = YES always. If before and after changing the deleting bool you run [tableView beginUpdates] and [tableView endUpdates] everything should work fine. Let me know if this doesn't make sense, and I'll try again.


Finally can show Reorder Control with Swipe-To-Delete in Non-Edit-Mode for row managed by Core Data NSFetchedResultsController in Swift 4.1 on Xcode 9.3 like this:

class MyTableViewCell: UITableViewCell {

    override func setEditing(_ editing: Bool, animated: Bool) {
        super.setEditing(editing, animated: animated)

        setupAccessoryView()
    }

    func setupAccessoryView() {
        if accessoryView == nil {
            if let reorderCtrl = subviews.first(where: { (subView) -> Bool in
                subView.description.contains("Reorder")
            }) {
                accessoryView = reorderCtrl
            }
        }
    }
}

class MyTableViewController: UITableViewController, NSFetchedResultsControllerDelegate {

    var frc: NSFetchedResultsController<MyRow>!

    override func viewDidLoad() {
        super.viewDidLoad()

        do {
            // Setup the NSFetchedResultsController here
            try frc.performFetch()

            setEditing(true, animated: false) // Enable for cell reorder control creation on first load
        } catch {
            print(error)
        }
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        setEditing(false, animated: false)
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)

        setEditing(true, animated: false) // Enable for cell reorder control creation when managed object is updated or inserted on other view
    }

    // MARK: - Table view data source

    override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
        // your data source update here for swipe to delete
    }

    override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
        // your data source update here for sort property value change
    }

}


I am not sure if this works with actual editing controls on top, but for just showing reordering controls all the time, this seems to be working best:

override func layoutSubviews() {
    showsReorderControl = true
    super.layoutSubviews()
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜