Forum Archive

How to implement swipe-to-delete in ListDataSource

wcaleb

I've looked at the documentation on this, but I'm having a hard time understanding how to implement a swipe-to-delete function in my Custom UI. I have the following set up and working:

data = ui.ListDataSource(items)  
view['tableview1'].data_source = data

Where items is a list of files in my DropBox that the custom UI displays, along with some other buttons and features. I want to implement a function whereby when I swipe on a list item and delete it, it deletes it from DropBox, and I don't need help with the code to do the actual deleting in DropBox. But I don't know how/where to define the tableview_delete function described here:

http://omz-software.com/editorial/docs/ios/ui.html#ui.TableView.data_source

Do I need to include that entire class block in my script? My Python fu is still limited, so any help with the syntax for defining that function would be much appreciated.

zrzka

ListDataSource is pretty limited. It helps with simple cases, but it doesn't provide:

  • deleted item,
  • deleted item index,
  • ...

Where to put your methods? Let's start from the beginning. TableView needs data_source to have a clue about data and it informs you about other actions like (de)selection via delegate. ListDataSource acts as data source and as delegate. There's no way to get info directly from TableView otherwise ListDataSource stops working. We have to check ListDataSource documentation if this object can inform us. And we are going to find:

  • action,
  • edit_action,
  • accessory_action,
  • selected_row,
  • tapped_accessory_row.

Almost there. edit_action is our friend. But it receives ListDataSource object as sender thus we have no clue which one was deleted (if it was). Same method is called for edit / move. We have to keep list of items elsewhere too and compare ListDataSource.items with our items to check what happened. Something like this ...

#coding: utf-8
import ui

items = [ 'a', 'b', 'c' ]

def item_edited(sender):
    removed = [x for x in items if x not in sender.items]
    if len(removed) == 1:       
        item = removed[0]
        print 'Item \'%s\' removed' % item
        items.remove(item)
    else:
        print 'Something\'s wrong, more than 1 removed item? With swipe to delete? Hmm ...'

def item_selected(sender):
    row = sender.selected_row
    if row != -1:
        print 'Item selected at index %d (\'%s\')' % ( row, sender.items[row] )

data_source = ui.ListDataSource(items)
data_source.delete_enabled = True
data_source.edit_action = item_edited
data_source.action = item_selected

view = ui.load_view()
view['tableview1'].data_source = data_source
view['tableview1'].delegate = data_source
view.present('sheet')

ListDataSource helps, is nice, but it's kinda limited (depends on your needs). If you reach limits, do it yourself.

#coding: utf-8
import ui

class MyDataSource (object):
    def __init__(self, items=[]):
        self.items = list(items)

    def tableview_number_of_sections(self, tableview):
        return 1

    def tableview_number_of_rows(self, tableview, section):
        return len(self.items)

    def tableview_cell_for_row(self, tableview, section, row):
        cell = ui.TableViewCell()
        cell.text_label.text = self.items[row]
        return cell

    def tableview_can_delete(self, tableview, section, row):
        return True

    def tableview_delete(self, tableview, section, row):
        print 'Item \'%s\' at %d row deleted' % ( self.items[row], row )
        del self.items[row]

class MyDelegate (object):
    def tableview_title_for_delete_button(self, tableview, section, row):
        return 'Trash It'

view = ui.load_view()
view['tableview1'].data_source = MyDataSource(['a', 'b', 'c'])
view['tableview1'].delegate = MyDelegate()
view.present('sheet')
wcaleb

Thanks for the helpful reply!