Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Swipe TableViewCell to show multiple actions
-
@colint strange, I don't have any freeze. I know that sometimes console.alert needs to be decorated by @ui.in_background, but here, I don't have the problem. Anyway, the challenge was to have several buttons when swiping, isn'it?
-
Strange, it must be just a problem on my end then. When I put ui.inbackground it doesn’t freeze, but the alerts show up behind the presented view, so I can only see them once I close the window. Anyway, like you said, as long as both actions show up then this is a good alternative way to do it! The only thing I’m wondering about now is if there is a way to get the same behaviour from the original solution, where a long swipe to the left would perform one of the actions. Thanks again for the help!
-
@colint said
long swipe
In the gestures module, the swipe function has min_distance and max_distance but they do not seem to work or you can't have two different swipes in the same direction.
Anyway, these parameters seem to belong to a private API, I think, and so it would be not allowed to be used.I try to get the width of the swipe gesture and to process differently for a short or a long swipe but, actually, without success.
Edit : I think that should be possible without using gestures but the standard touch_began/moved/ended methods where you can continuously compare finger movement from its begin to deduce if the swipe is short or long.
I could try but not this Sunday, normally tomorrow -
I could try but not this Sunday, normally tomorrow
Of course, no rush! That’s interesting, I didn’t know you could use touch_began, etc. with the ui module. I suppose it would need a little math to calculate which cell the touch was on but that should still be doable.
-
@colint said
would need a little math to calculate which cell the touch was
Not needed, try this draft of solution, not yet finished, very far of the end, only to let you know how it could work. I did not want to send something so early, only to show something you can try.
Don't describe me a list of bugs, I know 😂import console import ui class cell_view(ui.View): def __init__(self,w,h,tableview,row): self.width = w self.height = h self.tv = tableview self.row = row if self.tv.swiped: prev = self.tv.swiped prev['bdel'].x = self.width prev['byou'].x = prev['bdel'].x + prev['bdel'].width self.tv.swiped = self #self.border_width = 1 #self.border_color = 'red' bdel = ui.Button(name='bdel') bdel.frame = (w-0,0,w/8,self.height) bdel.background_color = 'red' bdel.tint_color = 'white' bdel.title = 'delete' bdel.action = self.but_action self.add_subview(bdel) byou = ui.Button(name='byou') byou.frame = (bdel.x+bdel.width,0,w/8,self.height) byou.background_color = 'green' byou.tint_color = 'white' byou.title = 'your edit' byou.action = self.but_action self.add_subview(byou) def touch_began(self, touch): #print('touch_began') self.x0,self.y0 = touch.location def touch_moved(self, touch): x,y = touch.location if abs(y-self.y0) < 100: # swipe if x < self.x0: # swipe left self['bdel'].x = max(self['bdel'].x + (x-touch.prev_location.x), self.width*3/4) self['byou'].x = self['bdel'].x + self['bdel'].width if self.tv.swiped: prev = self.tv.swiped if prev != self: prev['bdel'].x = self.width prev['byou'].x = prev['bdel'].x + prev['bdel'].width self.tv.swiped = self def touch_ended(self, touch): pass def but_action(self,sender): tbl = self.tv row = self.row self['bdel'].x = self.width self['byou'].x = self['bdel'].x + self['bdel'].width self.tv.swiped = None if sender.title == 'delete': b = console.alert('delete row',str(row), 'confirm', 'cancel', hide_cancel_button=True) if b == 1: del tbl.data_source.items[row] tbl.reload() elif sender.title == 'your edit': t = tbl.data_source.items[row] t = console.input_alert('enter text of row', str(row), t, 'ok', hide_cancel_button=True) tbl.data_source.items[row] = t class MyTableView(ui.View): def __init__(self,w,h): self.width = w self.height = h tbl = ui.TableView() tbl.swiped = None tbl.frame = (0,0,w,h) tbl.row_height = 50 tbl.data_source = ui.ListDataSource(items=['a','b','c','d','e']) tbl.delegate = self tbl.data_source.tableview_cell_for_row = self.tableview_cell_for_row tbl.data_source.tableview_can_delete = self.tableview_can_delete tbl.background_color = (0,0,0,0) self.add_subview(tbl) def tableview_cell_for_row(self, tableview, section, row): # Create and return a cell for the given section/row cell = ui.TableViewCell() cell.selectable = False cell.text_label.text = tableview.data_source.items[row] v = cell_view(self.width,tableview.row_height,tableview,row) cell.content_view.add_subview(v) return cell def tableview_can_delete(self, tableview, section, row): # Return True if the user should be able to delete the given row. return False # to be sure that standard delete button is not displayed def main(): # Hide script w,h = ui.get_screen_size() mi = min(w,h)*0.9 my_back = MyTableView(mi,mi) my_back.background_color='white' my_back.name = 'Test for @colint' my_back.present('sheet',hide_title_bar=False) my_back.wait_modal() # Protect against import if __name__ == '__main__': main()
-
@colint ok, I'll stop with this last code, surely not perfect but, I think, sufficient to show you that you can do it like you asked. Even long swipe (where delete button width is more than half screen) is foreseen and simulates the tap of the delete button. Try the code and give me some feed-back.
I'm sure that you could ameliorate it in a better way than mine,import console import ui class cell_view(ui.View): def __init__(self,w,h,tableview,row): self.width = w self.height = h self.tv = tableview self.row = row if self.tv.swiped: prev = self.tv.swiped prev['bdel'].x = self.width prev['byou'].x = prev['bdel'].x + prev['bdel'].width self.tv.swiped = self #self.border_width = 1 #self.border_color = 'red' bdel = ui.Button(name='bdel') bdel.frame = (w-0,0,w/8,self.height) bdel.background_color = 'red' bdel.tint_color = 'white' bdel.title = 'delete' bdel.action = self.but_action self.add_subview(bdel) byou = ui.Button(name='byou') byou.frame = (bdel.x+bdel.width,0,w/8,self.height) byou.background_color = 'green' byou.tint_color = 'white' byou.title = 'your edit' byou.action = self.but_action self.add_subview(byou) def touch_began(self, touch): #print('touch_began') if self.tv.swiped: prev = self.tv.swiped if prev != self: prev['bdel'].x = self.width prev['byou'].x = prev['bdel'].x + prev['bdel'].width self.tv.swiped = None self.x0,self.y0 = touch.location def touch_moved(self, touch): x,y = touch.location if abs(y-self.y0) < 100: # swipe left or right self['bdel'].x = min(max(self['bdel'].x + 2*(x-touch.prev_location.x), 0), self.width) self['bdel'].width = max(self.width/8,self.width*7/8-self['bdel'].x) #self['bdel'].x = min(max(self['bdel'].x + 2*(x-touch.prev_location.x), self.width*3/4), self.width) self['byou'].x = self['bdel'].x + self['bdel'].width self.tv.swiped = self def touch_ended(self, touch): if self['bdel'].width > self.width/2: # automatic delete self.but_action('simul delete button') def but_action(self,sender): tbl = self.tv row = self.row self['bdel'].x = self.width self['bdel'].width = self.width/8 self['byou'].x = self['bdel'].x + self['bdel'].width self.tv.swiped = None if sender.title == 'delete' or isinstance(sender, str): b = console.alert('delete row',str(row), 'confirm', 'cancel', hide_cancel_button=True) if b == 1: del tbl.data_source.items[row] tbl.reload() elif sender.title == 'your edit': t = tbl.data_source.items[row] t = console.input_alert('enter text of row', str(row), t, 'ok', hide_cancel_button=True) tbl.data_source.items[row] = t class MyTableView(ui.View): def __init__(self,w,h): self.width = w self.height = h tbl = ui.TableView() tbl.swiped = None tbl.frame = (0,0,w,h) tbl.row_height = 50 tbl.data_source = ui.ListDataSource(items=['a','b','c','d','e']) tbl.delegate = self tbl.data_source.tableview_cell_for_row = self.tableview_cell_for_row tbl.data_source.tableview_can_delete = self.tableview_can_delete tbl.background_color = (0,0,0,0) self.add_subview(tbl) def tableview_cell_for_row(self, tableview, section, row): # Create and return a cell for the given section/row cell = ui.TableViewCell() cell.selectable = False cell.text_label.text = tableview.data_source.items[row] v = cell_view(self.width,tableview.row_height,tableview,row) cell.content_view.add_subview(v) return cell def tableview_can_delete(self, tableview, section, row): # Return True if the user should be able to delete the given row. return False # to be sure that standard delete button is not displayed def main(): # Hide script w,h = ui.get_screen_size() mi = min(w,h)*0.9 my_back = MyTableView(mi,mi) my_back.background_color='white' my_back.name = 'Test for @colint' my_back.present('sheet',hide_title_bar=False) my_back.wait_modal() # Protect against import if __name__ == '__main__': main()
-
Looking good! I’m not seeing the “your edit” button sliding out all the way but I’m sure I can figure that out. Thanks so much for your help!
-
@colint said
I’m not seeing the “your edit” button sliding out all the way
Swipe left is not sufficient, obviously when you begin location is too much at left.
Could be done automatically by code -
Sounds good! I’ll take a look into it, thanks again!
-
This script saved me!
I was having trouble handling
tableView_cellForRowAtIndexPath_
inUITableViewDataSource
.I see that the value returned is
.ptr
.Thanks so much!